From 4dd589ef0e8143f09c9846fbd0ba2acd9750a150 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 10 Nov 2020 22:28:50 +0100 Subject: [PATCH 001/321] Master is now 1.9-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c6e282228..8783ad300 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.8.x-dev" + "dev-master": "1.9.x-dev" } } } From 08559b045e89341c14e9b36dd513b41c8a5cfdd2 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 16 Dec 2020 18:42:57 +0100 Subject: [PATCH 002/321] PHPLIB-605: Add note about filing docs ticket for compatibility changes --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7f1105f1b..1f8043bd8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -205,6 +205,7 @@ announced via [@MongoDB](http://twitter.com/mongodb) as well. ### Update compatibility tables in MongoDB docs -The [compatibility tables](https://docs.mongodb.com/drivers/driver-compatibility-reference#php-driver-compatibility) in -the MongoDB documentation must be updated to account for new releases. Make sure to update both MongoDB and Language +For minor releases, create a DOCSP ticket indicating whether there are changes to MongoDB Server or PHP version +compatibility. The [compatibility tables](https://docs.mongodb.com/drivers/driver-compatibility-reference#php-driver-compatibility) +in the MongoDB documentation must be updated to account for new releases. Make sure to update both MongoDB and Language compatibility tables, as shown in [this pull request](https://github.com/mongodb/docs-ecosystem/pull/642). From aa26460fcd1dbb262498470f2a1ebc1a476df1ff Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 16 Dec 2020 19:09:53 +0100 Subject: [PATCH 003/321] Skip failing tests on MongoDB 4.9 --- tests/FunctionalTestCase.php | 7 +++++++ tests/Model/IndexInfoFunctionalTest.php | 2 ++ 2 files changed, 9 insertions(+) diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 03d389677..aaaba5f42 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -393,6 +393,13 @@ protected function skipIfClientSideEncryptionIsNotSupported() } } + protected function skipIfGeoHaystackIndexIsNotSupported() + { + if (version_compare($this->getServerVersion(), '4.9', '>=')) { + $this->markTestSkipped('GeoHaystack indexes cannot be created in version 4.9 and above'); + } + } + protected function skipIfTransactionsAreNotSupported() { if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) { diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index d97a3ca23..4eb93c33d 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -51,6 +51,8 @@ public function testIs2dSphere() public function testIsGeoHaystack() { + $this->skipIfGeoHaystackIndexIsNotSupported(); + $indexName = $this->collection->createIndex(['pos' => 'geoHaystack', 'x' => 1], ['bucketSize' => 5]); $result = $this->collection->listIndexes(); From 716e2118f05bbdf9700008bc9afc20b193efe13a Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 17 Dec 2020 14:59:26 +0100 Subject: [PATCH 004/321] Disable failing PHPUnit due to deprecations --- .evergreen/run-tests.sh | 3 +++ .travis.yml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 423466503..91ba1d83f 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -22,6 +22,9 @@ echo "Running $AUTH tests over $SSL, connecting to $MONGODB_URI" OLD_PATH=$PATH PATH=/opt/php/${PHP_VERSION}-64bit/bin:$OLD_PATH +# Disable failing PHPUnit due to deprecations +SYMFONY_DEPRECATIONS_HELPER=999999 + # Run the tests, and store the results in a Evergreen compatible JSON results file case "$TESTS" in atlas-data-lake*) diff --git a/.travis.yml b/.travis.yml index 37b95219a..f41823caf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,7 +81,7 @@ before_script: script: - export MONGODB_URI=`cat /tmp/uri.txt` - echo $MONGODB_URI - - vendor/bin/simple-phpunit -v + - SYMFONY_DEPRECATIONS_HELPER=999999 vendor/bin/simple-phpunit -v before_cache: - rm -f ${HOME}/.cache/pip/log/debug.log From 5ea21b6b3928ffe3aa535f4fe0c59e4bc5d4df69 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 12 Jan 2021 08:13:26 -0500 Subject: [PATCH 005/321] PHPLIB-605: Update instructions for external doc updates (#800) --- CONTRIBUTING.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1f8043bd8..bf2337bb6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -203,9 +203,22 @@ Release announcements should also be sent to the [MongoDB Product & Driver Annou Consider announcing each release on Twitter. Significant releases should also be announced via [@MongoDB](http://twitter.com/mongodb) as well. -### Update compatibility tables in MongoDB docs +### Documentation Updates for New Major and Minor Versions + +New major and minor releases will also require documentation updates to other +projects: + + * Create a DOCSP ticket to add the new version to PHP's server and language + [compatibility tables](https://docs.mongodb.com/drivers/php/#compatibility) + in the driver docs portal. See + [mongodb/docs-ecosystem#642](https://github.com/mongodb/docs-ecosystem/pull/642) + for an example. + + * Create a DOCSP ticket to update the "current" and "upcoming" navigation links + in the library's [documentation](https://docs.mongodb.com/php-library/). This + will require updating + [mongodb/docs-php-library](https://github.com/mongodb/docs-php-library). + +These tasks can be initiated prior to tagging a new release to ensure that the +updated content becomes accessible soon after the release is published. -For minor releases, create a DOCSP ticket indicating whether there are changes to MongoDB Server or PHP version -compatibility. The [compatibility tables](https://docs.mongodb.com/drivers/driver-compatibility-reference#php-driver-compatibility) -in the MongoDB documentation must be updated to account for new releases. Make sure to update both MongoDB and Language -compatibility tables, as shown in [this pull request](https://github.com/mongodb/docs-ecosystem/pull/642). From b6d178f6738c5e0c8c3b49413d203c9d58f68460 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 13 Jan 2021 10:40:57 +0100 Subject: [PATCH 006/321] Export deprecations helper env var --- .evergreen/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 91ba1d83f..1d4b40907 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -23,7 +23,7 @@ OLD_PATH=$PATH PATH=/opt/php/${PHP_VERSION}-64bit/bin:$OLD_PATH # Disable failing PHPUnit due to deprecations -SYMFONY_DEPRECATIONS_HELPER=999999 +export SYMFONY_DEPRECATIONS_HELPER=999999 # Run the tests, and store the results in a Evergreen compatible JSON results file case "$TESTS" in From 931f3b359ec7176eb8edb6c8f202896bb7cc5921 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 20 Jan 2021 13:14:35 +0100 Subject: [PATCH 007/321] Use stable phpunit-bridge version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c6e282228..219257fdb 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ }, "require-dev": { "squizlabs/php_codesniffer": "^3.5, <3.5.5", - "symfony/phpunit-bridge": "5.x-dev" + "symfony/phpunit-bridge": "^5.2" }, "autoload": { "psr-4": { "MongoDB\\": "src/" }, From ec2f3ca1322541a0c849aab52aa83c95b41fc30f Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 20 Jan 2021 16:03:02 +0100 Subject: [PATCH 008/321] PHPLIB-606: Move CI checks from travis-ci to GitHub Actions (#802) * Move phpcs checks to GitHub actions * Test standalones on PHP 7.4 and PHP 8 on GitHub Actions * Use drivers-evergreen-tools to install and run MongoDB * Test PHP 8 on replica sets and sharded clusters * Remove travis-ci configs * Replace travis-ci badge with GitHub Actions badges * Fix server selection check for documentation examples * Ensure consistent build names * Fix fail-fast setting * Run CI checks on selected branches only * Explain using countDocuments to check for secondary servers --- .github/workflows/coding-standards.yml | 68 ++++++++++++++ .github/workflows/tests.yml | 97 ++++++++++++++++++++ .travis.yml | 93 -------------------- .travis/debug-core.sh | 10 --- .travis/get_uri.php | 6 -- .travis/install-extension.sh | 40 --------- .travis/mo.sh | 117 ------------------------- .travis/setup_mo.sh | 65 -------------- README.md | 3 +- tests/DocumentationExamplesTest.php | 18 ++-- 10 files changed, 178 insertions(+), 339 deletions(-) create mode 100644 .github/workflows/coding-standards.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 .travis.yml delete mode 100755 .travis/debug-core.sh delete mode 100644 .travis/get_uri.php delete mode 100755 .travis/install-extension.sh delete mode 100755 .travis/mo.sh delete mode 100755 .travis/setup_mo.sh diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml new file mode 100644 index 000000000..70be76d05 --- /dev/null +++ b/.github/workflows/coding-standards.yml @@ -0,0 +1,68 @@ +name: "Coding Standards" + +on: + pull_request: + branches: + - "v*.*" + - "master" + push: + branches: + - "v*.*" + - "master" + +jobs: + coding-standards: + name: "Coding Standards" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + php-version: + - "7.4" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php-version }} + extensions: "mongodb" + key: "extcache-v1" + + - name: Cache extensions + uses: actions/cache@v2 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ steps.extcache.outputs.key }} + restore-keys: ${{ steps.extcache.outputs.key }} + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + extensions: "mongodb" + php-version: "${{ matrix.php-version }}" + tools: "cs2pr" + + - name: "Show driver information" + run: "php --ri mongodb" + + - name: "Cache dependencies installed with Composer" + uses: "actions/cache@v2" + with: + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-locked-" + + - name: "Require doctrine/coding-standard" + run: "composer require --no-update doctrine/coding-standard=^6.0" + + - name: "Install dependencies with Composer" + run: "composer install --no-interaction --no-progress --no-suggest" + + # The -q option is required until phpcs v4 is released + - name: "Run PHP_CodeSniffer" + run: "vendor/bin/phpcs -q --no-colors --report=checkstyle | cs2pr" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..6287923f8 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,97 @@ +name: "Tests" + +on: + pull_request: + branches: + - "v*.*" + - "master" + push: + branches: + - "v*.*" + - "master" + +jobs: + phpunit: + name: "PHPUnit tests" + runs-on: "${{ matrix.os }}" + + strategy: + fail-fast: true + matrix: + os: + - "ubuntu-20.04" + php-version: + - "7.4" + - "8.0" + mongodb-version: + - "4.4" + driver-version: + - "stable" + topology: + - "server" + include: + - os: "ubuntu-20.04" + php-version: "8.0" + mongodb-version: "4.4" + driver-version: "stable" + topology: "replica_set" + - os: "ubuntu-20.04" + php-version: "8.0" + mongodb-version: "4.4" + driver-version: "stable" + topology: "sharded_cluster" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + with: + fetch-depth: 2 + + - id: setup-mongodb + uses: mongodb-labs/drivers-evergreen-tools@master + with: + version: ${{ matrix.mongodb-version }} + topology: ${{ matrix.topology }} + + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php-version }} + extensions: "mongodb-${{ matrix.driver-version }}" + key: "extcache-v1" + + - name: Cache extensions + uses: actions/cache@v2 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ steps.extcache.outputs.key }} + restore-keys: ${{ steps.extcache.outputs.key }} + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + tools: "pecl" + extensions: "mongodb-${{ matrix.driver-version }}" + coverage: "none" + ini-values: "zend.assertions=1" + + - name: "Show driver information" + run: "php --ri mongodb" + + - name: "Cache dependencies installed with composer" + uses: "actions/cache@v2" + with: + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-locked-" + + - name: "Install dependencies with composer" + run: "composer update --no-interaction --no-progress" + + - name: "Run PHPUnit" + run: "vendor/bin/simple-phpunit -v" + env: + SYMFONY_DEPRECATIONS_HELPER: 999999 + MONGODB_URI: ${{ steps.setup-mongodb.outputs.cluster-uri }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f41823caf..000000000 --- a/.travis.yml +++ /dev/null @@ -1,93 +0,0 @@ -language: php -dist: xenial -php: "7.4" - -addons: - apt: - packages: - - gdb - - libcurl3 - - libgssapi-krb5-2 - - libkrb5-dbg - - libldap-2.4-2 - - libpcap0.8 - - libsasl2-2 - - snmp - - openssl - -cache: - directories: - - ${HOME}/.cache/pip - - ${HOME}/.composer/cache/files - - ${HOME}/php-ext - -env: - global: - - DRIVER_VERSION=stable - - SERVER_DISTRO=enterprise-ubuntu1604 - - SERVER_VERSION=4.4.0 - - DEPLOYMENT=STANDALONE - - COMPOSER_OPTIONS= - -jobs: - include: - - - stage: Smoke Testing - env: - - CHECKS=phpunit - - stage: Smoke Testing - php: "7.1" - before_install: [] - before_script: - - .travis/install-extension.sh - - composer require --no-update doctrine/coding-standard=^6.0 - - composer install --no-interaction --no-progress --no-suggest ${COMPOSER_OPTIONS} - script: vendor/bin/phpcs - after_script: [] - after_failure: [] - env: - - CHECKS=phpcs - - # Test against PHP 8 - - stage: Test - php: "8.0snapshot" - - stage: Test - php: "8.0snapshot" - env: - - DEPLOYMENT=REPLICASET - - stage: Test - php: "8.0snapshot" - env: - - DEPLOYMENT=SHARDED_CLUSTER_RS - -before_install: - - pip install "mongo-orchestration>=0.6.7,<1.0" --user `whoami` - - export SERVER_FILENAME=mongodb-linux-x86_64-${SERVER_DISTRO}-${SERVER_VERSION} - - wget -qO- https://downloads.mongodb.com/linux/${SERVER_FILENAME}.tgz | tar xz - - export PATH=${PWD}/${SERVER_FILENAME}/bin:${PATH} - - mongod --version - - mongo-orchestration --version - - export MO_PATH=`python -c 'import mongo_orchestration; from os import path; print(path.dirname(mongo_orchestration.__file__));'` - -before_script: - - mongo-orchestration start - - .travis/setup_mo.sh - - .travis/install-extension.sh - - php --ri mongodb - - composer update --no-interaction --no-progress --no-suggest --prefer-dist --prefer-stable ${COMPOSER_OPTIONS} - - ulimit -c - - ulimit -c unlimited -S - -script: - - export MONGODB_URI=`cat /tmp/uri.txt` - - echo $MONGODB_URI - - SYMFONY_DEPRECATIONS_HELPER=999999 vendor/bin/simple-phpunit -v - -before_cache: - - rm -f ${HOME}/.cache/pip/log/debug.log - -after_failure: - - find . -name 'core*' -exec ${TRAVIS_BUILD_DIR}/.travis/debug-core.sh {} \; - -after_script: - - mongo-orchestration stop diff --git a/.travis/debug-core.sh b/.travis/debug-core.sh deleted file mode 100755 index 6a2a01eec..000000000 --- a/.travis/debug-core.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -if [ "${TRAVIS_OS_NAME}" = "osx" ]; then - # https://www.ics.uci.edu/~pattis/common/handouts/macmingweclipse/allexperimental/mac-gdb-install.html - echo "Cannot debug core files on macOS: ${1}" - exit 1 -fi - -PHP_BINARY=`which php` -gdb -batch -ex "bt full" -ex "quit" "${PHP_BINARY}" "${1}" diff --git a/.travis/get_uri.php b/.travis/get_uri.php deleted file mode 100644 index 9c1c42895..000000000 --- a/.travis/get_uri.php +++ /dev/null @@ -1,6 +0,0 @@ -$uriField, $uriSuffix; diff --git a/.travis/install-extension.sh b/.travis/install-extension.sh deleted file mode 100755 index 9f99f71b5..000000000 --- a/.travis/install-extension.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -INI=~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini -# tpecl is a helper to compile and cache php extensions -tpecl () { - local ext_name=$1 - local ext_so=$2 - local ext_dir=$(php -r "echo ini_get('extension_dir');") - local ext_cache=~/php-ext/$(basename $ext_dir)/$ext_name - if [[ -e $ext_cache/$ext_so ]]; then - echo extension = $ext_cache/$ext_so >> $INI - else - mkdir -p $ext_cache - echo yes | pecl install -f $ext_name && - cp $ext_dir/$ext_so $ext_cache - fi -} - -if [ "x${DRIVER_BRANCH}" != "x" ] || [ "x${DRIVER_REPO}" != "x" ]; then - CLONE_REPO=${DRIVER_REPO:-https://github.com/mongodb/mongo-php-driver} - CHECKOUT_BRANCH=${DRIVER_BRANCH:-master} - - echo "Compiling driver branch ${CHECKOUT_BRANCH} from repository ${CLONE_REPO}" - - mkdir -p /tmp/compile - git clone ${CLONE_REPO} /tmp/compile/mongo-php-driver - cd /tmp/compile/mongo-php-driver - - git checkout ${CHECKOUT_BRANCH} - git submodule update --init - phpize - ./configure --enable-mongodb-developer-flags - make all -j20 > /dev/null - make install - - echo "extension=mongodb.so" >> `php --ini | grep "Scan for additional .ini files in" | sed -e "s|.*:\s*||"`/mongodb.ini -elif [ "x${DRIVER_VERSION}" != "x" ]; then - echo "Installing driver version ${DRIVER_VERSION} from PECL" - tpecl mongodb-${DRIVER_VERSION} mongodb.so -fi diff --git a/.travis/mo.sh b/.travis/mo.sh deleted file mode 100755 index 13941ddb8..000000000 --- a/.travis/mo.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash -# Copyright 2012-2014 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. - -function eval_params { - local params=$(sed -e 's|["]|\\\"|g' $1) - echo $(eval echo \"$params\") -} - -function r { - echo $1| awk -F'/' '{print $(NF-1)}'| sed 's/standalone/servers/' -} - -function a { - echo $(cd $(dirname $1); pwd)/$(basename $1) -} - -function id { - local id_line=$(grep id $1 | head -n 1) - echo $(expr "$id_line" : '.*: *"\(.*\)" *,*') -} - -function get { - echo "GET $1 $(curl --header 'Accept: application/json' --include --silent --request GET $1)" -} - -function post { - echo "POST $1 $(curl --header 'Accept: application/json' --include --silent --request POST --data "$2" $1)" -} - -function delete { - echo "DELETE $1 $(curl --header 'Accept: application/json' --include --silent --request DELETE $1)" -} - -function code { - expr "$1" : '.*HTTP/1.[01] \([0-9]*\)' -} - -function usage { - echo "usage: $0 configurations/cluster/file.json action" - echo "cluster: servers|replica_sets|sharded_clusters" - echo "action: start|status|stop" - exit 1 -} - -SSL_FILES=$(a ./ssl-files) -BASE_URL=${MONGO_ORCHESTRATION:-'http://localhost:8889'} - -if [ $# -ne 2 ]; then usage; fi -if [ ! -f "$1" ]; then echo "configuration file '$1' not found"; exit 1; fi - -ID=$(id $1) -if [ ! "$ID" ]; then echo "id field not found in configuration file '$1'"; exit 1; fi -R=$(r $1) - -GET=$(get $BASE_URL/$R/$ID) -HTTP_CODE=$(code "$GET") -EXIT_CODE=0 - -case $2 in -start) - if [ "$HTTP_CODE" != "200" ] - then - WORKSPACE=${TRAVIS_BUILD_DIR}/orchestrations - rm -fr $WORKSPACE - mkdir $WORKSPACE - LOGPATH=$WORKSPACE - DBPATH=$WORKSPACE - POST_DATA=$(eval_params $1) - echo "DBPATH=$DBPATH" - echo "LOGPATH=$LOGPATH" - echo "POST_DATA='$POST_DATA'" - echo - POST=$(post $BASE_URL/$R "$POST_DATA") - echo "$POST" - HTTP_CODE=$(code "$POST") - if [ "$HTTP_CODE" != 200 ]; then EXIT_CODE=1; fi - else - echo "$GET" - fi - ;; -stop) - if [ "$HTTP_CODE" == "200" ] - then - DELETE=$(delete $BASE_URL/$R/$ID) - echo "$DELETE" - HTTP_CODE=$(code "$DELETE") - if [ "$HTTP_CODE" != 204 ]; then EXIT_CODE=1; fi - else - echo "$GET" - fi - ;; -status) - if [ "$HTTP_CODE" == "200" ] - then - echo "$GET" - else - echo "$GET" - EXIT_CODE=1 - fi - ;; -*) - usage - ;; -esac -exit $EXIT_CODE diff --git a/.travis/setup_mo.sh b/.travis/setup_mo.sh deleted file mode 100755 index cf8c3cea8..000000000 --- a/.travis/setup_mo.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -echo Loading MO for $DEPLOYMENT - -if [[ -z $TRAVIS_BUILD_DIR ]]; then - export TRAVIS_BUILD_DIR=`pwd`; -fi - -# Replace the default client certificate with the new one to make sure mo keeps working -cp ${TRAVIS_BUILD_DIR}/mongo-orchestration/ssl/client.pem ${MO_PATH}/lib/client.pem - -URI_FIELD="mongodb_uri" -URI_SUFFIX="" - -case $DEPLOYMENT in - SHARDED_CLUSTER) - CONFIG="sharded_clusters/cluster.json" - URI_SUFFIX="/?retryWrites=false" - ;; - SHARDED_CLUSTER_RS) - CONFIG="sharded_clusters/cluster_replset.json" - ;; - STANDALONE_AUTH) - CONFIG="standalone/standalone-auth.json" - URI_FIELD="mongodb_auth_uri" - ;; - STANDALONE_OLD) - CONFIG="standalone/standalone-old.json" - ;; - STANDALONE_SSL) - CONFIG="standalone/standalone-ssl.json" - URI_SUFFIX="/?ssl=true&sslallowinvalidcertificates=true" - ;; - REPLICASET) - CONFIG="replica_sets/replicaset.json" - ;; - REPLICASET_SINGLE) - CONFIG="replica_sets/replicaset-one-node.json" - ;; - REPLICASET_OLD) - CONFIG="replica_sets/replicaset-old.json" - ;; - *) - CONFIG="standalone/standalone.json" - ;; -esac - -${TRAVIS_BUILD_DIR}/.travis/mo.sh ${TRAVIS_BUILD_DIR}/mongo-orchestration/$CONFIG start > /tmp/mo-result.json - -if [ $? -ne 0 ]; then - cat /tmp/mo-result.json - cat ${TRAVIS_BUILD_DIR}/server.log - exit 1 -fi - -cat /tmp/mo-result.json | tail -n 1 | php ${TRAVIS_BUILD_DIR}/.travis/get_uri.php $URI_FIELD $URI_SUFFIX > /tmp/uri.txt - -echo -n "MongoDB Test URI: " -cat /tmp/uri.txt -echo - -echo "Raw MO Response:" -cat /tmp/mo-result.json - -echo diff --git a/README.md b/README.md index cc8bdd9af..8a8db4cdc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # MongoDB PHP Library -[![Build Status](https://api.travis-ci.org/mongodb/mongo-php-library.png?branch=master)](https://travis-ci.org/mongodb/mongo-php-library) +![Tests](https://github.com/mongodb/mongo-php-library/workflows/Tests/badge.svg) +![Coding Standards](https://github.com/mongodb/mongo-php-library/workflows/Coding%20Standards/badge.svg) This library provides a high-level abstraction around the lower-level [PHP driver](https://github.com/mongodb/mongo-php-driver) (`mongodb` extension). diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index c59058ce9..3d483a072 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -7,7 +7,7 @@ use MongoDB\Client; use MongoDB\Database; use MongoDB\Driver\Cursor; -use MongoDB\Driver\Exception\ConnectionTimeoutException; +use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; @@ -1466,12 +1466,6 @@ public function testCausalConsistency() { $this->skipIfCausalConsistencyIsNotSupported(); - try { - $this->manager->selectServer(new ReadPreference('secondary')); - } catch (ConnectionTimeoutException $e) { - $this->markTestSkipped('Secondary is not available'); - } - $this->assertNotNull('This test intentionally performs no assertions'); // Prep @@ -1486,6 +1480,16 @@ public function testCausalConsistency() [ 'sku' => '111', 'name' => 'Peanuts', 'start' => new UTCDateTime() ] ); + try { + /* In sharded clusters, server selection ignores the read preference + * mode, so using $manager->selectServer does not work here. To work + * around this, we run a query on a secondary and rely on an + * exception to let us know that no secondary is available. */ + $items->countDocuments([], ['readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY)]); + } catch (Exception $e) { + $this->markTestSkipped('Secondary is not available'); + } + // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly // Start Causal Consistency Example 1 $items = $client->selectDatabase( From 3c6b5f2999574d3e8d479195363a7ee241e1a584 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 20 Jan 2021 18:26:08 +0100 Subject: [PATCH 009/321] PHPLIB-598: Clean up cursor usages to account for iterator changes (#801) * Bump required ext-mongodb version * Remove unnecessary cursor wrapping for iterators * Update tailable cursor documentation to account for cursor changes * Apply review feedback to docs * Update evergreen config to no longer test against 1.8 driver --- .evergreen/config.yml | 8 +-- composer.json | 2 +- docs/tutorial/tailable-cursor.txt | 59 ++++++++++----------- src/GridFS/ReadableStream.php | 8 ++- src/Model/CachingIterator.php | 8 +-- src/Model/CallbackIterator.php | 4 +- tests/Collection/CrudSpecFunctionalTest.php | 5 +- tests/GridFS/SpecFunctionalTest.php | 5 +- tests/Operation/FindFunctionalTest.php | 18 +++---- tests/SpecTests/FunctionalTestCase.php | 3 +- tests/SpecTests/PrimaryStepDownSpecTest.php | 16 +++--- tests/UnifiedSpecTests/CollectionData.php | 3 +- 12 files changed, 61 insertions(+), 78 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 2755f9966..a1b4b93c5 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -435,17 +435,13 @@ axes: display_name: Driver Version values: - id: "lowest-supported" - display_name: "1.8.1" + display_name: "1.9.0" variables: - DRIVER_VERSION: "1.8.1" + DRIVER_VERSION: "1.9.0" - id: "latest-stable" display_name: "1.9-stable" variables: DRIVER_VERSION: "stable" - - id: "1.8-dev" - display_name: "1.8-dev" - variables: - DRIVER_BRANCH: "v1.8" - id: "1.9-dev" display_name: "1.9-dev" variables: diff --git a/composer.json b/composer.json index 23ed9e672..c36c266e9 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.0 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.8.1", + "ext-mongodb": "^1.9.0", "jean85/pretty-package-versions": "^1.2", "symfony/polyfill-php80": "^1.19" }, diff --git a/docs/tutorial/tailable-cursor.txt b/docs/tutorial/tailable-cursor.txt index c4ff3b0eb..2c84b080b 100644 --- a/docs/tutorial/tailable-cursor.txt +++ b/docs/tutorial/tailable-cursor.txt @@ -18,7 +18,7 @@ Overview When the driver executes a query or command (e.g. :manual:`aggregate `), results from the operation are returned via a :php:`MongoDB\\Driver\\Cursor ` -object. The Cursor class implements PHP's :php:`Traversable ` +object. The Cursor class implements PHP's :php:`Iterator ` interface, which allows it to be iterated with ``foreach`` and interface with any PHP functions that work with :php:`iterables `. Similar to result objects in other database drivers, cursors in MongoDB only support @@ -35,20 +35,21 @@ While normal cursors can be iterated once with ``foreach``, that approach will not work with tailable cursors. When ``foreach`` is used with a tailable cursor, the loop will stop upon reaching the end of the initial result set. Attempting to continue iteration on the cursor with a second ``foreach`` would throw an -exception, since PHP attempts to rewind the cursor. +exception, since PHP attempts to rewind the cursor. Therefore, reading from a +tailable cursor will require direct usage of the :php:`Iterator ` API. -In order to continuously read from a tailable cursor, we will need to wrap the -Cursor object with an :php:`IteratorIterator `. This will -allow us to directly control the cursor's iteration (e.g. call ``next()``), -avoid inadvertently rewinding the cursor, and decide when to wait for new -results or stop iteration entirely. +.. note:: + + Before version 1.9.0 of the ``ext-mongodb`` extension, the cursor class does + not implement the :php:`Iterator ` interface. To manually iterate + a cursor using the method below, it must first be wrapped with an + :php:`IteratorIterator `. -Wrapping a Normal Cursor ------------------------- +Manually Iterating a Normal Cursor +---------------------------------- -Before looking at how a tailable cursor can be wrapped with -:php:`IteratorIterator `, we'll start by examining how the -class interacts with a normal cursor. +Before looking at how a tailable cursor can be iterated, we'll start by +examining how the ``Iterator`` methods interact with a normal cursor. The following example finds five restaurants and uses ``foreach`` to view the results: @@ -74,7 +75,7 @@ not occurred, the iterator then advances to the next position, control jumps back to the validity check, and the loop continues. With the inner workings of ``foreach`` under our belt, we can now translate the -preceding example to use IteratorIterator: +preceding example to use the Iterator methods directly: .. code-block:: php @@ -84,28 +85,26 @@ preceding example to use IteratorIterator: $cursor = $collection->find([], ['limit' => 5]); - $iterator = new IteratorIterator($cursor); + $cursor->rewind(); - $iterator->rewind(); - - while ($iterator->valid()) { - $document = $iterator->current(); + while ($cursor->valid()) { + $document = $cursor->current(); var_dump($document); - $iterator->next(); + $cursor->next(); } .. note:: - Calling ``$iterator->next()`` after the ``while`` loop naturally ends would + Calling ``$cursor->next()`` after the ``while`` loop naturally ends would throw an exception, since all results on the cursor have been exhausted. The purpose of this example is simply to demonstrate the functional equivalence between ``foreach`` and manual iteration with PHP's :php:`Iterator ` -API. For normal cursors, there is little reason to use IteratorIterator instead -of a concise ``foreach`` loop. +API. For normal cursors, there is little reason to manually iterate results +instead of a concise ``foreach`` loop. -Wrapping a Tailable Cursor --------------------------- +Iterating a Tailable Cursor +--------------------------- In order to demonstrate a tailable cursor in action, we'll need two scripts: a "producer" and a "consumer". The producer script will create a new capped @@ -154,7 +153,7 @@ If you execute this consumer script, you'll notice that it quickly exhausts all results in the capped collection and then terminates. We cannot add a second ``foreach``, as that would throw an exception when attempting to rewind the cursor. This is a ripe use case for directly controlling the iteration process -using :php:`IteratorIterator `. +using the :php:`Iterator ` interface. .. code-block:: php @@ -167,17 +166,15 @@ using :php:`IteratorIterator `. 'maxAwaitTimeMS' => 100, ]); - $iterator = new IteratorIterator($cursor); - - $iterator->rewind(); + $cursor->rewind(); while (true) { - if ($iterator->valid()) { - $document = $iterator->current(); + if ($cursor->valid()) { + $document = $cursor->current(); printf("Consumed document created at: %s\n", $document->createdAt); } - $iterator->next(); + $cursor->next(); } Much like the ``foreach`` example, this version on the consumer script will diff --git a/src/GridFS/ReadableStream.php b/src/GridFS/ReadableStream.php index 7978de972..c49474eb1 100644 --- a/src/GridFS/ReadableStream.php +++ b/src/GridFS/ReadableStream.php @@ -17,7 +17,7 @@ namespace MongoDB\GridFS; -use IteratorIterator; +use MongoDB\Driver\CursorInterface; use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\Exception\CorruptFileException; use stdClass; @@ -48,7 +48,7 @@ class ReadableStream /** @var integer */ private $chunkOffset = 0; - /** @var IteratorIterator|null */ + /** @var CursorInterface|null */ private $chunksIterator; /** @var CollectionWrapper */ @@ -315,9 +315,7 @@ private function initBufferFromNextChunk() */ private function initChunksIterator() { - $cursor = $this->collectionWrapper->findChunksByFileId($this->file->_id, $this->chunkOffset); - - $this->chunksIterator = new IteratorIterator($cursor); + $this->chunksIterator = $this->collectionWrapper->findChunksByFileId($this->file->_id, $this->chunkOffset); $this->chunksIterator->rewind(); } } diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index 3eb94b22d..d4419d073 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -41,7 +41,7 @@ class CachingIterator implements Countable, Iterator /** @var array */ private $items = []; - /** @var IteratorIterator */ + /** @var Iterator */ private $iterator; /** @var boolean */ @@ -53,14 +53,14 @@ class CachingIterator implements Countable, Iterator /** * Initialize the iterator and stores the first item in the cache. This * effectively rewinds the Traversable and the wrapping IteratorIterator. - * Additionally, this mimics behavior of the SPL iterators and allows users - * to omit an explicit call * to rewind() before using the other methods. + * Additionally, this mimics behavior of the SPL iterators and allows users + * to omit an explicit call to rewind() before using the other methods. * * @param Traversable $traversable */ public function __construct(Traversable $traversable) { - $this->iterator = new IteratorIterator($traversable); + $this->iterator = $traversable instanceof Iterator ? $traversable : new IteratorIterator($traversable); $this->iterator->rewind(); $this->storeCurrentItem(); diff --git a/src/Model/CallbackIterator.php b/src/Model/CallbackIterator.php index 23b7c1035..82afa925e 100644 --- a/src/Model/CallbackIterator.php +++ b/src/Model/CallbackIterator.php @@ -32,12 +32,12 @@ class CallbackIterator implements Iterator /** @var Closure */ private $callback; - /** @var IteratorIterator */ + /** @var Iterator */ private $iterator; public function __construct(Traversable $traversable, Closure $callback) { - $this->iterator = new IteratorIterator($traversable); + $this->iterator = $traversable instanceof Iterator ? $traversable : new IteratorIterator($traversable); $this->callback = $callback; } diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index 0b33dcbc0..69204421d 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -2,7 +2,6 @@ namespace MongoDB\Tests\Collection; -use IteratorIterator; use LogicException; use MongoDB\BulkWriteResult; use MongoDB\Collection; @@ -105,8 +104,8 @@ public function provideSpecificationTests() private function assertEquivalentCollections($expectedCollection, $actualCollection) { $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - $mi->attachIterator(new IteratorIterator($expectedCollection->find())); - $mi->attachIterator(new IteratorIterator($actualCollection->find())); + $mi->attachIterator($expectedCollection->find()); + $mi->attachIterator($actualCollection->find()); foreach ($mi as $documents) { list($expectedDocument, $actualDocument) = $documents; diff --git a/tests/GridFS/SpecFunctionalTest.php b/tests/GridFS/SpecFunctionalTest.php index f9d42f3f8..6d08e0ef9 100644 --- a/tests/GridFS/SpecFunctionalTest.php +++ b/tests/GridFS/SpecFunctionalTest.php @@ -3,7 +3,6 @@ namespace MongoDB\Tests\GridFS; use DateTime; -use IteratorIterator; use LogicException; use MongoDB\BSON\Binary; use MongoDB\BSON\ObjectId; @@ -121,8 +120,8 @@ public function provideSpecificationTests() private function assertEquivalentCollections($expectedCollection, $actualCollection, $actualResult) { $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - $mi->attachIterator(new IteratorIterator($expectedCollection->find())); - $mi->attachIterator(new IteratorIterator($actualCollection->find())); + $mi->attachIterator($expectedCollection->find()); + $mi->attachIterator($actualCollection->find()); foreach ($mi as $documents) { list($expectedDocument, $actualDocument) = $documents; diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php index 1aff69e50..0b22cdf53 100644 --- a/tests/Operation/FindFunctionalTest.php +++ b/tests/Operation/FindFunctionalTest.php @@ -2,7 +2,6 @@ namespace MongoDB\Tests\Operation; -use IteratorIterator; use MongoDB\Driver\BulkWrite; use MongoDB\Driver\ReadPreference; use MongoDB\Operation\CreateCollection; @@ -183,27 +182,26 @@ public function testMaxAwaitTimeMS() $operation = new Find($databaseName, $cappedCollectionName, [], ['cursorType' => Find::TAILABLE_AWAIT, 'maxAwaitTimeMS' => $maxAwaitTimeMS]); $cursor = $operation->execute($this->getPrimaryServer()); - $it = new IteratorIterator($cursor); /* The initial query includes the one and only document in its result * batch, so we should not expect a delay. */ $startTime = microtime(true); - $it->rewind(); + $cursor->rewind(); $duration = microtime(true) - $startTime; $this->assertLessThan($pivot, $duration); - $this->assertTrue($it->valid()); - $this->assertSameDocument(['_id' => 1], $it->current()); + $this->assertTrue($cursor->valid()); + $this->assertSameDocument(['_id' => 1], $cursor->current()); /* Advancing again takes us to the last document of the result batch, * but still should not issue a getMore */ $startTime = microtime(true); - $it->next(); + $cursor->next(); $duration = microtime(true) - $startTime; $this->assertLessThan($pivot, $duration); - $this->assertTrue($it->valid()); - $this->assertSameDocument(['_id' => 2], $it->current()); + $this->assertTrue($cursor->valid()); + $this->assertSameDocument(['_id' => 2], $cursor->current()); /* Now that we've reached the end of the initial result batch, advancing * again will issue a getMore. Expect to wait at least maxAwaitTimeMS, @@ -211,12 +209,12 @@ public function testMaxAwaitTimeMS() * query thread. Also ensure we don't wait too long (server default is * one second). */ $startTime = microtime(true); - $it->next(); + $cursor->next(); $duration = microtime(true) - $startTime; $this->assertGreaterThan($pivot, $duration); $this->assertLessThan(0.5, $duration); - $this->assertFalse($it->valid()); + $this->assertFalse($cursor->valid()); } public function testReadPreferenceWithinTransaction() diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index 1c0a76803..b6d48a213 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -3,7 +3,6 @@ namespace MongoDB\Tests\SpecTests; use ArrayIterator; -use IteratorIterator; use LogicException; use MongoDB\Collection; use MongoDB\Driver\Server; @@ -106,7 +105,7 @@ protected function assertOutcomeCollectionData(array $expectedDocuments, $result $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); $mi->attachIterator(new ArrayIterator($expectedDocuments)); - $mi->attachIterator(new IteratorIterator($outcomeCollection->find([], ['sort' => ['_id' => 1]]))); + $mi->attachIterator($outcomeCollection->find([], ['sort' => ['_id' => 1]])); foreach ($mi as $documents) { list($expectedDocument, $actualDocument) = $documents; diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php index 986c1a477..53c215e6c 100644 --- a/tests/SpecTests/PrimaryStepDownSpecTest.php +++ b/tests/SpecTests/PrimaryStepDownSpecTest.php @@ -2,7 +2,6 @@ namespace MongoDB\Tests\SpecTests; -use IteratorIterator; use MongoDB\Client; use MongoDB\Collection; use MongoDB\Driver\Command; @@ -205,12 +204,11 @@ public function testGetMoreIteration() // Start a find operation on the collection with a batch size of 2, and retrieve the first batch of results. $cursor = $this->collection->find([], ['batchSize' => 2]); - $iterator = new IteratorIterator($cursor); - $iterator->rewind(); - $this->assertTrue($iterator->valid()); + $cursor->rewind(); + $this->assertTrue($cursor->valid()); - $iterator->next(); - $this->assertTrue($iterator->valid()); + $cursor->next(); + $this->assertTrue($cursor->valid()); $totalConnectionsCreated = $this->getTotalConnectionsCreated(); @@ -235,14 +233,14 @@ public function testGetMoreIteration() $events = []; $observer = new CommandObserver(); $observer->observe( - function () use ($iterator) { - $iterator->next(); + function () use ($cursor) { + $cursor->next(); }, function ($event) use (&$events) { $events[] = $event; } ); - $this->assertTrue($iterator->valid()); + $this->assertTrue($cursor->valid()); $this->assertCount(1, $events); $this->assertSame('getMore', $events[0]['started']->getCommandName()); diff --git a/tests/UnifiedSpecTests/CollectionData.php b/tests/UnifiedSpecTests/CollectionData.php index c81615a9f..33f0cea46 100644 --- a/tests/UnifiedSpecTests/CollectionData.php +++ b/tests/UnifiedSpecTests/CollectionData.php @@ -3,7 +3,6 @@ namespace MongoDB\Tests\UnifiedSpecTests; use ArrayIterator; -use IteratorIterator; use MongoDB\Client; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; @@ -75,7 +74,7 @@ public function assertOutcome(Client $client) $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); $mi->attachIterator(new ArrayIterator($this->documents)); - $mi->attachIterator(new IteratorIterator($cursor)); + $mi->attachIterator($cursor); foreach ($mi as $i => $documents) { list($expectedDocument, $actualDocument) = $documents; From ae3dc591e8ded359cd52c61c75e8c305a19314b3 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Mon, 25 Jan 2021 12:43:36 +0100 Subject: [PATCH 010/321] PHPLIB-608 Fix wrong validity check in CachingIterator (#803) * PHPLIB-608 Fix wrong validity check in CachingIterator * Apply review feedback --- src/Model/CachingIterator.php | 6 ++--- tests/Model/CachingIteratorTest.php | 41 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index d4419d073..b904ecae3 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -153,12 +153,10 @@ private function exhaustIterator() */ private function storeCurrentItem() { - $key = $this->iterator->key(); - - if ($key === null) { + if (! $this->iterator->valid()) { return; } - $this->items[$key] = $this->iterator->current(); + $this->items[$this->iterator->key()] = $this->iterator->current(); } } diff --git a/tests/Model/CachingIteratorTest.php b/tests/Model/CachingIteratorTest.php index f4d4b28bf..0306d8491 100644 --- a/tests/Model/CachingIteratorTest.php +++ b/tests/Model/CachingIteratorTest.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\Model; use Exception; +use Iterator; use MongoDB\Model\CachingIterator; use MongoDB\Tests\TestCase; use Throwable; @@ -110,6 +111,46 @@ public function testCountWithEmptySet() $this->assertCount(0, $iterator); } + /** + * This protects against iterators that return valid keys on invalid + * positions, which was the case in ext-mongodb until PHPC-1748 was fixed. + */ + public function testWithWrongIterator() + { + $nestedIterator = new class implements Iterator { + /** @var int */ + private $i = 0; + + public function current() + { + return $this->i; + } + + public function next() + { + $this->i++; + } + + public function key() + { + return $this->i; + } + + public function valid() + { + return $this->i == 0; + } + + public function rewind() + { + $this->i = 0; + } + }; + + $iterator = new CachingIterator($nestedIterator); + $this->assertCount(1, $iterator); + } + private function getTraversable($items) { foreach ($items as $item) { From 99f11bbeb4961317c332fe3adbae7c81b312d294 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 1 Feb 2021 11:05:41 -0500 Subject: [PATCH 011/321] PHPLIB-611: Ensure valid-fail tests are executed by unified test runner (#804) --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 5090692fe..c33f1d52e 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -2,6 +2,7 @@ namespace MongoDB\Tests\UnifiedSpecTests; +use Exception; use MongoDB\Client; use MongoDB\Collection; use MongoDB\Driver\Exception\ServerException; @@ -11,7 +12,6 @@ use MongoDB\Tests\FunctionalTestCase; use stdClass; use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; -use Throwable; use function file_get_contents; use function gc_collect_cycles; use function glob; @@ -87,10 +87,7 @@ private function doTearDown() parent::tearDown(); } - /** - * @dataProvider providePassingTests - */ - public function testPassingTests(stdClass $test, string $schemaVersion, array $runOnRequirements = null, array $createEntities = null, array $initialData = null) + private function doTestCase(stdClass $test, string $schemaVersion, array $runOnRequirements = null, array $createEntities = null, array $initialData = null) { if (! $this->isSchemaVersionSupported($schemaVersion)) { $this->markTestIncomplete(sprintf('Test format schema version "%s" is not supported', $schemaVersion)); @@ -144,6 +141,14 @@ public function testPassingTests(stdClass $test, string $schemaVersion, array $r } } + /** + * @dataProvider providePassingTests + */ + public function testPassingTests(...$args) + { + $this->doTestCase(...$args); + } + public function providePassingTests() { return $this->provideTests(__DIR__ . '/valid-pass'); @@ -157,11 +162,13 @@ public function testFailingTests(...$args) // Cannot use expectException(), as it ignores PHPUnit Exceptions $failed = false; + // phpcs:disable SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException try { - $this->testCase(...$args); - } catch (Throwable $e) { + $this->doTestCase(...$args); + } catch (Exception $e) { $failed = true; } + // phpcs:enable assertTrue($failed, 'Expected test to throw an exception'); } From 4c7d5cb71fd3d3f2965856a00e37c07f2646fa86 Mon Sep 17 00:00:00 2001 From: Alessandro Lai Date: Tue, 9 Feb 2021 08:39:52 +0100 Subject: [PATCH 012/321] Allow PrettyVersion 2.0 (#805) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index c36c266e9..4e2faa080 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "ext-hash": "*", "ext-json": "*", "ext-mongodb": "^1.9.0", - "jean85/pretty-package-versions": "^1.2", + "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, "require-dev": { From 39d77454c58e765726e8e655aeab25220b0442e8 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 9 Feb 2021 08:40:44 +0100 Subject: [PATCH 013/321] Cleanup scripts in .evergreen directory (#808) * Remove obsolete orchestration config * Remove unnecessary files --- .evergreen/compile-unix.sh | 67 ---- .evergreen/compile-windows.sh | 49 --- .evergreen/compile.sh | 30 -- .evergreen/config.yml | 2 +- .evergreen/download-mongodb.sh | 391 ------------------------ .evergreen/generate_task_config.py | 31 -- .evergreen/install-dependencies.sh | 4 +- .evergreen/make-docs.sh | 26 -- .evergreen/make-release.sh | 13 - .evergreen/orchestration/db/.empty | 0 .evergreen/orchestration/lib/client.pem | 48 --- .evergreen/run-atlas-proxy.sh | 104 ------- .evergreen/run-orchestration.sh | 108 ------- .evergreen/start-orchestration.sh | 78 ----- .evergreen/stop-orchestration.sh | 12 - 15 files changed, 2 insertions(+), 961 deletions(-) delete mode 100755 .evergreen/compile-unix.sh delete mode 100755 .evergreen/compile-windows.sh delete mode 100755 .evergreen/compile.sh delete mode 100755 .evergreen/download-mongodb.sh delete mode 100644 .evergreen/generate_task_config.py delete mode 100644 .evergreen/make-docs.sh delete mode 100644 .evergreen/make-release.sh delete mode 100644 .evergreen/orchestration/db/.empty delete mode 100644 .evergreen/orchestration/lib/client.pem delete mode 100755 .evergreen/run-atlas-proxy.sh delete mode 100755 .evergreen/run-orchestration.sh delete mode 100644 .evergreen/start-orchestration.sh delete mode 100755 .evergreen/stop-orchestration.sh diff --git a/.evergreen/compile-unix.sh b/.evergreen/compile-unix.sh deleted file mode 100755 index 7591c3241..000000000 --- a/.evergreen/compile-unix.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - -# Supported/used environment variables: -# MARCH Machine Architecture. Defaults to lowercase uname -m -# RELEASE Use the fully qualified release archive - -RELEASE=${RELEASE:-no} - - -# Automatically retrieve the machine architecture, lowercase, unless provided -# as an environment variable (e.g. to force 32bit) -[ -z "$MARCH" ] && MARCH=$(uname -m | tr '[:upper:]' '[:lower:]') - -# Get the kernel name, lowercased -OS=$(uname -s | tr '[:upper:]' '[:lower:]') -echo "OS: $OS" - -# --strip-components is an GNU tar extension. Check if the platform -# (e.g. Solaris) has GNU tar installed as `gtar`, otherwise we assume to be on -# platform that supports it -# command -v returns success error code if found and prints the path to it -if command -v gtar 2>/dev/null; then - TAR=gtar -else - TAR=tar -fi - -# Any architecture specific configuration here -case "$MARCH" in - i386) - CFLAGS="$CFLAGS -m32 -march=i386" - ;; - x86_64) - CFLAGS="$CFLAGS -m64 -march=x86-64" - ;; - ppc64le) - CFLAGS="$CFLAGS -mcpu=power8 -mtune=power8 -mcmodel=medium" - ;; -esac - - -# Operating system specific tweaks -case "$OS" in - darwin) - ;; - - linux) - # Make linux builds a tad faster by parallelise the build - cpus=$(grep -c '^processor' /proc/cpuinfo) - MAKEFLAGS="-j${cpus}" - ;; - - sunos) - # Most normal build tools on the Solaris servers lives here - PATH="/opt/mongodbtoolchain/bin:$PATH" - ;; -esac - -echo "MARCH: $MARCH" -echo "RELEASE: $RELEASE" -echo "OS: $OS" - - -#./configure -make diff --git a/.evergreen/compile-windows.sh b/.evergreen/compile-windows.sh deleted file mode 100755 index 33349bb34..000000000 --- a/.evergreen/compile-windows.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -set -o igncr # Ignore CR in this script -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - -# Supported/used environment variables: -# CC Which compiler to use - - -case "$CC" in - # 64bit specific configuration - *Win64) - ;; - # 32bit specific configuration - *) - ;; -esac - -# Resolve the compiler name to correct MSBuild location -case "$CC" in - "Visual Studio 10 2010") - BUILD="/cygdrive/c/Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe" - ;; - "Visual Studio 10 2010 Win64") - BUILD="/cygdrive/c/Windows/Microsoft.NET/Framework64/v4.0.30319/MSBuild.exe" - ;; - "Visual Studio 12 2013") - BUILD="/cygdrive/c/Program Files (x86)/MSBuild/12.0/Bin/MSBuild.exe" - ;; - "Visual Studio 12 2013 Win64") - BUILD="/cygdrive/c/Program Files (x86)/MSBuild/12.0/Bin/MSBuild.exe" - ;; - "Visual Studio 14 2015") - BUILD="/cygdrive/c/Program Files (x86)/MSBuild/14.0/Bin/MSBuild.exe" - ;; - "Visual Studio 14 2015 Win64") - BUILD="/cygdrive/c/Program Files (x86)/MSBuild/14.0/Bin/MSBuild.exe" - ;; -esac - -export PATH=$PATH:`pwd`/tests:`pwd`/Debug:`pwd`/src/libbson/Debug -CMAKE="/cygdrive/c/cmake/bin/cmake" -INSTALL_DIR="C:/install-dir" - - -"$CMAKE" -G "$CC" "-DCMAKE_INSTALL_PREFIX=${INSTALL_DIR}" "-DBSON_ROOT_DIR=${INSTALL_DIR}" $CONFIGURE_FLAGS -"$BUILD" /m ALL_BUILD.vcxproj -"$BUILD" /m INSTALL.vcxproj - diff --git a/.evergreen/compile.sh b/.evergreen/compile.sh deleted file mode 100755 index 8b7820e99..000000000 --- a/.evergreen/compile.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - - -DIR=$(dirname $0) - -OS=$(uname -s | tr '[:upper:]' '[:lower:]') -BUILDTOOL=${BUILDTOOL:-autotools} - -case "$OS" in - cygwin*) - sh $DIR/compile-windows.sh - ;; - - *) - # If compiling using multiple different build tools or variants - # that require wildly different scripting, - # this would be a good place to call the different scripts - case "$BUILDTOOL" in - cmake) - sh $DIR/compile-unix-cmake.sh - ;; - autotools) - sh $DIR/compile-unix.sh - ;; - esac - ;; -esac - diff --git a/.evergreen/config.yml b/.evergreen/config.yml index a1b4b93c5..f2ad6a598 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -174,7 +174,7 @@ functions: params: script: | ${PREPARE_SHELL} - MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} sh ${PROJECT_DIRECTORY}/.evergreen/run-orchestration.sh + MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: diff --git a/.evergreen/download-mongodb.sh b/.evergreen/download-mongodb.sh deleted file mode 100755 index 26238667d..000000000 --- a/.evergreen/download-mongodb.sh +++ /dev/null @@ -1,391 +0,0 @@ -#!/bin/sh - -#For future use the feed to get full list of distros : http://downloads.mongodb.org/full.json - -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - -get_distro () -{ - if [ -f /etc/os-release ]; then - . /etc/os-release - DISTRO="${ID}-${VERSION_ID}" - elif command -v lsb_release >/dev/null 2>&1; then - name=$(lsb_release -s -i) - if [ "$name" = "RedHatEnterpriseServer" ]; then # RHEL 6.2 at least - name="rhel" - fi - version=$(lsb_release -s -r) - DISTRO="${name}-${version}" - elif [ -f /etc/redhat-release ]; then - release=$(cat /etc/redhat-release) - - if [[ "$release" =~ "Red Hat" ]]; then - name="rhel" - elif [[ "$release" =~ "Fedora" ]]; then - name="fedora" - fi - version=$(echo $release | sed 's/.*\([[:digit:]]\).*/\1/g') - DISTRO="${name}-${version}" - elif [ -f /etc/lsb-release ]; then - . /etc/lsb-release - DISTRO="${DISTRIB_ID}-${DISTRIB_RELEASE}" - elif grep -R "Amazon Linux" "/etc/system-release" >/dev/null 2>&1; then - DISTRO="amzn64" - fi - - OS_NAME=$(uname -s) - MARCH=$(uname -m) - DISTRO=$(echo "$OS_NAME-$DISTRO-$MARCH" | tr '[:upper:]' '[:lower:]') - - echo $DISTRO -} - -# get_mongodb_download_url_for "linux-distro-version-architecture" "latest|40|36|34|32|30|28|26|24" -# Sets EXTRACT to aproprate extract command -# Sets MONGODB_DOWNLOAD_URL to the aproprate download url -get_mongodb_download_url_for () -{ - _DISTRO=$1 - _VERSION=$2 - - VERSION_44="v4.4-latest" - VERSION_42="4.2.5" - VERSION_40="4.0.17" - VERSION_36="3.6.17" - VERSION_34="3.4.24" - VERSION_32="3.2.22" - VERSION_30="3.0.15" - VERSION_26="2.6.12" - VERSION_24="2.4.14" - - EXTRACT="tar zxf" - # getdata matrix on: - # https://evergreen.mongodb.com/version/5797f0493ff12235e5001f05 - case "$_DISTRO" in - darwin*) - MONGODB_LATEST="http://downloads.10gen.com/osx/mongodb-macos-x86_64-enterprise-latest.tgz" - MONGODB_44="http://downloads.10gen.com/osx/mongodb-macos-x86_64-enterprise-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/osx/mongodb-macos-x86_64-enterprise-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/osx/mongodb-osx-x86_64-enterprise-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/osx/mongodb-osx-x86_64-enterprise-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/osx/mongodb-osx-x86_64-enterprise-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/osx/mongodb-osx-x86_64-enterprise-${VERSION_32}.tgz" - MONGODB_30="https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-${VERSION_30}.tgz" - MONGODB_26="https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-${VERSION_26}.tgz" - MONGODB_24="https://fastdl.mongodb.org/osx/mongodb-osx-x86_64-${VERSION_24}.tgz" - ;; - sunos*i86pc) - MONGODB_LATEST="https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-latest.tgz" - MONGODB_34="https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-3.4.5.tgz" - MONGODB_32="https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-3.2.14.tgz" - MONGODB_30="https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-${VERSION_30}.tgz" - MONGODB_26="https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-${VERSION_26}.tgz" - MONGODB_24="https://fastdl.mongodb.org/sunos5/mongodb-sunos5-x86_64-${VERSION_24}.tgz" - ;; - linux-rhel-8*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel80-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel80-${VERSION_44}.tgz" - ;; - linux-rhel-7*-s390x) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel72-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel72-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel72-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel72-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel72-3.6.4.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel72-3.4.14.tgz" - ;; - linux-rhel-7.1-ppc64le) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-rhel71-${VERSION_32}.tgz" - ;; - linux-rhel-7.0*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_32}.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel70-${VERSION_26}.tgz" - ;; - linux-rhel-6*-s390x) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel67-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel67-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel67-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel67-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel67-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-rhel67-${VERSION_34}.tgz" - ;; - linux-rhel-6.2*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_32}.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-rhel62-${VERSION_26}.tgz" - MONGODB_24="http://downloads.10gen.com/linux/mongodb-linux-x86_64-subscription-rhel62-${VERSION_24}.tgz" - ;; - linux-rhel-5.5*) - MONGODB_LATEST="http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel55-latest.tgz" - MONGODB_32="http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel55-${VERSION_32}.tgz" - MONGODB_30="http://downloads.mongodb.org/linux/mongodb-linux-x86_64-rhel55-${VERSION_30}.tgz" - ;; - linux-sles-11*-x86_64) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse11-latest.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse11-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse11-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse11-${VERSION_32}.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse11-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse11-${VERSION_26}.tgz" - MONGODB_24="http://downloads.10gen.com/linux/mongodb-linux-x86_64-subscription-suse11-${VERSION_24}.tgz" - ;; - linux-sles-12*-s390x) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-suse12-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-suse12-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-suse12-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-suse12-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-suse12-3.6.3.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-suse12-3.4.13.tgz" - ;; - linux-sles-12*-x86_64) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-suse12-${VERSION_32}.tgz" - ;; - linux-amzn-2018*-x86_64) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_32}.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amzn64-${VERSION_26}.tgz" - MONGODB_24="http://downloads.10gen.com/linux/mongodb-linux-x86_64-subscription-amzn64-${VERSION_24}.tgz" - ;; - linux-amzn-2-x86_64) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amazon2-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amazon2-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amazon2-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-amazon2-${VERSION_40}.tgz" - ;; - linux-debian-7*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian71-latest.tgz" - # SERVER-32999 removed support for Debian 7. - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian71-3.6.5.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian71-3.4.15.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian71-3.2.20.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian71-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian71-${VERSION_26}.tgz" - ;; - linux-debian-8*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian81-latest.tgz" - # SERVER-37767 Removed support for Debian 8 - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian81-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian81-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian81-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian81-${VERSION_32}.tgz" - ;; - linux-debian-9*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian92-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian92-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian92-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian92-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian92-${VERSION_36}.tgz" - ;; - linux-debian-10*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian10-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-debian10-${VERSION_44}.tgz" - ;; - linux-ubuntu-18.04-s390x) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1804-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1804-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1804-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1804-${VERSION_40}.tgz" - ;; - linux-ubuntu-18.04-aarch64) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-aarch64-enterprise-ubuntu1804-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-aarch64-enterprise-ubuntu1804-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-aarch64-enterprise-ubuntu1804-${VERSION_42}.tgz" - ;; - linux-ubuntu-18.04-ppc64le) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1804-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1804-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1804-${VERSION_42}.tgz" - ;; - linux-ubuntu-18.04*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1804-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1804-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1804-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1804-${VERSION_40}.tgz" - ;; - linux-ubuntu-16.04-s390x) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1604-latest.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1604-v4.0-latest.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1604-3.6.4.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-s390x-enterprise-ubuntu1604-3.4.14.tgz" - ;; - linux-ubuntu-16.04-ppc64le) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1604-latest.tgz" - # SERVER-37774 Removed support for Ubuntu 16.04 PPCLE - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1604-4.0.9.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1604-3.6.12.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-ppc64le-enterprise-ubuntu1604-3.4.20.tgz" - ;; - linux-ubuntu-16.04-aarch64) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-aarch64-enterprise-ubuntu1604-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-aarch64-enterprise-ubuntu1604-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-aarch64-enterprise-ubuntu1604-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-arm64-enterprise-ubuntu1604-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-arm64-enterprise-ubuntu1604-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-arm64-enterprise-ubuntu1604-${VERSION_34}.tgz" - ;; - linux-ubuntu-16.04*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-latest.tgz" - MONGODB_44="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-${VERSION_44}.tgz" - MONGODB_42="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-${VERSION_42}.tgz" - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-${VERSION_40}.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-${VERSION_36}.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-${VERSION_34}.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1604-${VERSION_32}.tgz" - ;; - linux-ubuntu-14.04*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-latest.tgz" - # SERVER-37765 Removed support for Ubuntu 14.04 - MONGODB_40="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-4.0.9.tgz" - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-3.6.12.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-3.4.20.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-${VERSION_32}.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1404-${VERSION_26}.tgz" - ;; - linux-ubuntu-12.04*) - MONGODB_LATEST="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1204-latest.tgz" - # SERVER-31535 removed support for Ubuntu 12. - MONGODB_36="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1204-3.6.3.tgz" - MONGODB_34="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1204-3.4.14.tgz" - MONGODB_32="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1204-3.2.19.tgz" - MONGODB_30="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1204-${VERSION_30}.tgz" - MONGODB_26="http://downloads.10gen.com/linux/mongodb-linux-x86_64-enterprise-ubuntu1204-${VERSION_26}.tgz" - MONGODB_24="http://downloads.10gen.com/linux/mongodb-linux-x86_64-subscription-ubuntu1204-${VERSION_24}.tgz" - ;; - windows32*) - EXTRACT="/cygdrive/c/Progra~2/7-Zip/7z.exe x" - MONGODB_32="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_32}.zip" - MONGODB_30="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_30}.zip" - MONGODB_26="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_26}.zip" - MONGODB_24="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_24}.zip" - ;; - windows64*) - # same as cygwin*-86-64 - EXTRACT="/cygdrive/c/Progra~2/7-Zip/7z.exe x" - MONGODB_LATEST="http://downloads.10gen.com/windows/mongodb-windows-x86_64-enterprise-latest.zip" - MONGODB_44="http://downloads.10gen.com/windows/mongodb-windows-x86_64-enterprise-${VERSION_44}.zip" - MONGODB_42="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_42}.zip" - MONGODB_40="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_40}.zip" - MONGODB_36="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_36}.zip" - MONGODB_34="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_34}.zip" - MONGODB_32="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_32}.zip" - MONGODB_30="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_30}.zip" - MONGODB_26="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_26}.zip" - MONGODB_24="https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-${VERSION_24}.zip" - ;; - cygwin*-x86_64) - EXTRACT="/cygdrive/c/Progra~2/7-Zip/7z.exe x" - MONGODB_LATEST="http://downloads.10gen.com/windows/mongodb-windows-x86_64-enterprise-latest.zip" - MONGODB_44="http://downloads.10gen.com/windows/mongodb-windows-x86_64-enterprise-${VERSION_44}.zip" - MONGODB_42="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_42}.zip" - MONGODB_40="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_40}.zip" - MONGODB_36="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_36}.zip" - MONGODB_34="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_34}.zip" - MONGODB_32="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_32}.zip" - MONGODB_30="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_30}.zip" - MONGODB_26="http://downloads.10gen.com/win32/mongodb-win32-x86_64-enterprise-windows-64-${VERSION_26}.zip" - MONGODB_24="https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-${VERSION_24}.zip" - ;; - cygwin*-i686) - EXTRACT="/cygdrive/c/Progra~1/7-Zip/7z.exe x" - MONGODB_32="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_32}.zip" - MONGODB_30="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_30}.zip" - MONGODB_26="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_26}.zip" - MONGODB_24="https://fastdl.mongodb.org/win32/mongodb-win32-i386-${VERSION_24}.zip" - ;; - esac - - # Fallback to generic Linux x86_64 builds (without SSL) when no platform specific link is available. - case "$_DISTRO" in - *linux*x86_64) - MONGODB_LATEST=${MONGODB_LATEST:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-latest.tgz"} - # SERVER-37316 Removed support for generic linux builds. - MONGODB_42=${MONGODB_42:-""} - MONGODB_40=${MONGODB_40:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_40}.tgz"} - MONGODB_36=${MONGODB_36:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_36}.tgz"} - MONGODB_34=${MONGODB_34:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_34}.tgz"} - MONGODB_32=${MONGODB_32:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_32}.tgz"} - MONGODB_30=${MONGODB_30:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_30}.tgz"} - MONGODB_26=${MONGODB_26:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_26}.tgz"} - MONGODB_24=${MONGODB_24:-"http://downloads.mongodb.org/linux/mongodb-linux-x86_64-${VERSION_24}.tgz"} - ;; - esac - - # PYTHON-2238 On Archlinux MongoDB <= 3.2 requires LC_ALL=C. - case "$_DISTRO" in - linux-arch-*) - case "$_VERSION" in - 3.2) export LC_ALL=C ;; - 3.0) export LC_ALL=C ;; - 2.6) export LC_ALL=C ;; - 2.4) export LC_ALL=C ;; - esac - ;; - esac - - case "$_VERSION" in - latest) MONGODB_DOWNLOAD_URL=$MONGODB_LATEST ;; - 4.4) MONGODB_DOWNLOAD_URL=$MONGODB_44 ;; - 4.2) MONGODB_DOWNLOAD_URL=$MONGODB_42 ;; - 4.0) MONGODB_DOWNLOAD_URL=$MONGODB_40 ;; - 3.6) MONGODB_DOWNLOAD_URL=$MONGODB_36 ;; - 3.4) MONGODB_DOWNLOAD_URL=$MONGODB_34 ;; - 3.2) MONGODB_DOWNLOAD_URL=$MONGODB_32 ;; - 3.0) MONGODB_DOWNLOAD_URL=$MONGODB_30 ;; - 2.6) MONGODB_DOWNLOAD_URL=$MONGODB_26 ;; - 2.4) MONGODB_DOWNLOAD_URL=$MONGODB_24 ;; - esac - - [ -z "$MONGODB_DOWNLOAD_URL" ] && MONGODB_DOWNLOAD_URL="Unknown version: $_VERSION for $_DISTRO" - - echo $MONGODB_DOWNLOAD_URL -} - -download_and_extract () -{ - MONGODB_DOWNLOAD_URL=$1 - EXTRACT=$2 - - cd $DRIVERS_TOOLS - curl --retry 8 -sS $MONGODB_DOWNLOAD_URL --max-time 300 --output mongodb-binaries.tgz - $EXTRACT mongodb-binaries.tgz - - rm mongodb-binaries.tgz - mv mongodb* mongodb - chmod -R +x mongodb - find . -name vcredist_x64.exe -exec {} /install /quiet \; - ./mongodb/bin/mongod --version - cd - -} diff --git a/.evergreen/generate_task_config.py b/.evergreen/generate_task_config.py deleted file mode 100644 index 3820cc400..000000000 --- a/.evergreen/generate_task_config.py +++ /dev/null @@ -1,31 +0,0 @@ -import itertools - - -TASK_TEMPLATE = ''' - - name: "test-{version}-{topology}" - tags: ["{version}", "{topology}"] - commands: - - func: "bootstrap mongo-orchestration" - vars: - VERSION: "{version}" - TOPOLOGY: "{mo_topology}" - - func: "run tests"''' - -MONGODB_VERSIONS = ['2.4', '2.6', '3.0', '3.2', '3.4', 'latest'] -TOPOLOGY_OPTIONS = ['standalone', 'replica_set', 'sharded_cluster'] - - -def create_task(version, topology): - mo_topology= topology - # mongo-orchestration uses 'server' as the name for 'standalone' - if mo_topology == 'standalone': - mo_topology = 'server' - return TASK_TEMPLATE.format(**locals()) - - -tasks = [] -for version, topology in itertools.product(MONGODB_VERSIONS, - TOPOLOGY_OPTIONS): - tasks.append(create_task(version, topology)) - -print('\n'.join(tasks)) diff --git a/.evergreen/install-dependencies.sh b/.evergreen/install-dependencies.sh index 9ccd2dc10..289c80209 100644 --- a/.evergreen/install-dependencies.sh +++ b/.evergreen/install-dependencies.sh @@ -40,14 +40,12 @@ install_extension () sudo cp ${PROJECT_DIRECTORY}/.evergreen/config/php.ini ${PHP_PATH}/lib/php.ini } -DIR=$(dirname $0) # Functions to fetch MongoDB binaries -. $DIR/download-mongodb.sh +. ${DRIVERS_TOOLS}/.evergreen/download-mongodb.sh OS=$(uname -s | tr '[:upper:]' '[:lower:]') get_distro -# See .evergreen/download-mongodb.sh for most possible values case "$DISTRO" in cygwin*) echo "Install Windows dependencies" diff --git a/.evergreen/make-docs.sh b/.evergreen/make-docs.sh deleted file mode 100644 index f61da5a4b..000000000 --- a/.evergreen/make-docs.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - - -mkdir -p doc/html || true - - -cat < doc/html/index.html > doc/html/intro.html - - - -EOT - -cat <> doc/html/index.html -This is an example of a doc page automatically uploaded to evergreen so you can see your docs rendered. -The evergreen URL differs for patch builds and normal builds -EOT -cat <> doc/html/intro.html -This page is never actually uploaded by evergreen, only the index page was uploaded. -Thats why there is a link to the index page ("Rendered docs") while this is not an actual artifact. -This page was uploaded seperately with the s3cmd tools -EOT diff --git a/.evergreen/make-release.sh b/.evergreen/make-release.sh deleted file mode 100644 index ef6e2af7e..000000000 --- a/.evergreen/make-release.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - - -echo "Creating Release Archive Bundle RPM" - -echo "The release archive will have the version automatically derived from the nearest git tag for patchbuilds, otherwise 'latest' is used" - -echo "The release file should be called $PROJECT.tar.gz" - - -cd .. && tar czf $PROJECT.tar.gz src diff --git a/.evergreen/orchestration/db/.empty b/.evergreen/orchestration/db/.empty deleted file mode 100644 index e69de29bb..000000000 diff --git a/.evergreen/orchestration/lib/client.pem b/.evergreen/orchestration/lib/client.pem deleted file mode 100644 index 5b0700109..000000000 --- a/.evergreen/orchestration/lib/client.pem +++ /dev/null @@ -1,48 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAsNS8UEuin7/K29jXfIOLpIoh1jEyWVqxiie2Onx7uJJKcoKo -khA3XeUnVN0k6X5MwYWcN52xcns7LYtyt06nRpTG2/emoV44w9uKTuHsvUbiOwSV -m/ToKQQ4FUFZoqorXH+ZmJuIpJNfoW+3CkE1vEDCIecIq6BNg5ySsPtvSuSJHGjp -mc7/5ZUDvFE2aJ8QbJU3Ws0HXiEb6ymi048LlzEL2VKX3w6mqqh+7dcZGAy7qYk2 -5FZ9ktKvCeQau7mTyU1hsPrKFiKtMN8Q2ZAItX13asw5/IeSTq2LgLFHlbj5Kpq4 -GmLdNCshzH5X7Ew3IYM8EHmsX8dmD6mhv7vpVwIDAQABAoIBABOdpb4qhcG+3twA -c/cGCKmaASLnljQ/UU6IFTjrsjXJVKTbRaPeVKX/05sgZQXZ0t3s2mV5AsQ2U1w8 -Cd+3w+qaemzQThW8hAOGCROzEDX29QWi/o2sX0ydgTMqaq0Wv3SlWv6I0mGfT45y -/BURIsrdTCvCmz2erLqa1dL4MWJXRFjT9UTs5twlecIOM2IHKoGGagFhymRK4kDe -wTRC9fpfoAgyfus3pCO/wi/F8yKGPDEwY+zgkhrJQ+kSeki7oKdGD1H540vB8gRt -EIqssE0Y6rEYf97WssQlxJgvoJBDSftOijS6mwvoasDUwfFqyyPiirawXWWhHXkc -DjIi/XECgYEA5xfjilw9YyM2UGQNESbNNunPcj7gDZbN347xJwmYmi9AUdPLt9xN -3XaMqqR22k1DUOxC/5hH0uiXir7mDfqmC+XS/ic/VOsa3CDWejkEnyGLiwSHY502 -wD/xWgHwUiGVAG9HY64vnDGm6L3KGXA2oqxanL4V0+0+Ht49pZ16i8sCgYEAw+Ox -CHGtpkzjCP/z8xr+1VTSdpc/4CP2HONnYopcn48KfQnf7Nale69/1kZpypJlvQSG -eeA3jMGigNJEkb8/kaVoRLCisXcwLc0XIfCTeiK6FS0Ka30D/84Qm8UsHxRdpGkM -kYITAa2r64tgRL8as4/ukeXBKE+oOhX43LeEfyUCgYBkf7IX2Ndlhsm3GlvIarxy -NipeP9PGdR/hKlPbq0OvQf9R1q7QrcE7H7Q6/b0mYNV2mtjkOQB7S2WkFDMOP0P5 -BqDEoKLdNkV/F9TOYH+PCNKbyYNrodJOt0Ap6Y/u1+Xpw3sjcXwJDFrO+sKqX2+T -PStG4S+y84jBedsLbDoAEwKBgQCTz7/KC11o2yOFqv09N+WKvBKDgeWlD/2qFr3w -UU9K5viXGVhqshz0k5z25vL09Drowf1nAZVpFMO2SPOMtq8VC6b+Dfr1xmYIaXVH -Gu1tf77CM9Zk/VSDNc66e7GrUgbHBK2DLo+A+Ld9aRIfTcSsMbNnS+LQtCrQibvb -cG7+MQKBgQCY11oMT2dUekoZEyW4no7W5D74lR8ztMjp/fWWTDo/AZGPBY6cZoZF -IICrzYtDT/5BzB0Jh1f4O9ZQkm5+OvlFbmoZoSbMzHL3oJCBOY5K0/kdGXL46WWh -IRJSYakNU6VIS7SjDpKgm9D8befQqZeoSggSjIIULIiAtYgS80vmGA== ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDgzCCAmugAwIBAgIDAxOUMA0GCSqGSIb3DQEBCwUAMHkxGzAZBgNVBAMTEkRy -aXZlcnMgVGVzdGluZyBDQTEQMA4GA1UECxMHRHJpdmVyczEQMA4GA1UEChMHTW9u -Z29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsx -CzAJBgNVBAYTAlVTMB4XDTE5MDUyMjIzNTU1NFoXDTM5MDUyMjIzNTU1NFowaTEP -MA0GA1UEAxMGY2xpZW50MRAwDgYDVQQLEwdEcml2ZXJzMQwwCgYDVQQKEwNNREIx -FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD -VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALDUvFBLop+/ -ytvY13yDi6SKIdYxMllasYontjp8e7iSSnKCqJIQN13lJ1TdJOl+TMGFnDedsXJ7 -Oy2LcrdOp0aUxtv3pqFeOMPbik7h7L1G4jsElZv06CkEOBVBWaKqK1x/mZibiKST -X6FvtwpBNbxAwiHnCKugTYOckrD7b0rkiRxo6ZnO/+WVA7xRNmifEGyVN1rNB14h -G+spotOPC5cxC9lSl98Opqqofu3XGRgMu6mJNuRWfZLSrwnkGru5k8lNYbD6yhYi -rTDfENmQCLV9d2rMOfyHkk6ti4CxR5W4+SqauBpi3TQrIcx+V+xMNyGDPBB5rF/H -Zg+pob+76VcCAwEAAaMkMCIwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF -BwMCMA0GCSqGSIb3DQEBCwUAA4IBAQAqRcLAGvYMaGYOV4HJTzNotT2qE0I9THNQ -wOV1fBg69x6SrUQTQLjJEptpOA288Wue6Jt3H+p5qAGV5GbXjzN/yjCoItggSKxG -Xg7279nz6/C5faoIKRjpS9R+MsJGlttP9nUzdSxrHvvqm62OuSVFjjETxD39DupE -YPFQoHOxdFTtBQlc/zIKxVdd20rs1xJeeU2/L7jtRBSPuR/Sk8zot7G2/dQHX49y -kHrq8qz12kj1T6XDXf8KZawFywXaz0/Ur+fUYKmkVk1T0JZaNtF4sKqDeNE4zcns -p3xLVDSl1Q5Gwj7bgph9o4Hxs9izPwiqjmNaSjPimGYZ399zcurY ------END CERTIFICATE----- diff --git a/.evergreen/run-atlas-proxy.sh b/.evergreen/run-atlas-proxy.sh deleted file mode 100755 index edfdb7bc9..000000000 --- a/.evergreen/run-atlas-proxy.sh +++ /dev/null @@ -1,104 +0,0 @@ -#!/bin/sh -# -# This script uses the Atlas proxy project's own evergreen launch script -# to build and launch an Atlas proxy for testing. It works directly from -# their master branch, so may fail if they break something. -# -# There is no corresponding 'shutdown' script; the Atlas proxy project -# relies on Evergreen to terminate processes and clean up when tasks end, -# so we do the same. -# -# The URI is harded coded as: -# mongodb://user:pencil@host5.local.10gen.cc:9900/admin?replicaSet=benchmark -# -# Connections requires SSL and the CA file is 'main/ca.pem' in the atlasproxy repo. -# -# If this fails, check the 'main/test.sh' file in the atlasproxy repo for -# possible changes. -# -# Installation of Go dependencies appears to require a newer git. 1.7 on -# rhel62 failed, but 2.0 on ubuntu1604 worked. The atlasproxy project -# itself tests on rhel70. -# -# This script expects the following environment variables: -# -# DRIVERS_TOOLS (required) - absolute path to the checked out -# driver-evergreen-tools repository -# -# MONGODB_VERSION - version of MongoDB to download and use. For Atlas -# Proxy, must be "3.4" or "latest". Defaults to "3.4". - -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - -MONGODB_VERSION=${MONGODB_VERSION:-"3.4"} - -ORIG_DIR="$(pwd)" - -#--------------------------------------------------------------------------# -# Downlaod MongoDB Binary -#--------------------------------------------------------------------------# - -DL_START=$(date +%s) -DIR=$(dirname $0) - -# Load download helper functions -. $DIR/download-mongodb.sh - -# set $DISTRO -get_distro - -# set $MONGODB_DOWNLOAD_URL and $EXTRACT -get_mongodb_download_url_for "$DISTRO" "$MONGODB_VERSION" - -# extracts to $DRIVERS_TOOLS/mongodb -rm -rf "$DRIVERS_TOOLS/mongodb" -download_and_extract "$MONGODB_DOWNLOAD_URL" "$EXTRACT" -DL_END=$(date +%s) - -#--------------------------------------------------------------------------# -# Clone Atlas Proxy repo and launch it -#--------------------------------------------------------------------------# - -AP_START=$(date +%s) - -cd "$ORIG_DIR" -rm -rf atlasproxy -git clone git@github.com:10gen/atlasproxy.git -cd atlasproxy - -# This section copied from atlasproxy's .evergreen.yml: <<< -export PATH="/opt/golang/go1.11/bin:$PATH" -export GOROOT="/opt/golang/go1.11" -export GOPATH=`pwd`/.gopath -go version -./gpm -export MONGO_DIR="$DRIVERS_TOOLS/mongodb/bin" -cd main -./start_test_proxies_and_mtms.sh -# >>> end of copy - -AP_END=$(date +%s) - -# Write results file -DL_ELAPSED=$(expr $DL_END - $DL_START) -AP_ELAPSED=$(expr $AP_END - $AP_START) -cat <> $DRIVERS_TOOLS/results.json -{"results": [ - { - "status": "PASS", - "test_file": "AtlasProxy Start", - "start": $AP_START, - "end": $AP_END, - "elapsed": $AP_ELAPSED - }, - { - "status": "PASS", - "test_file": "Download MongoDB", - "start": $DL_START, - "end": $DL_END, - "elapsed": $DL_ELAPSED - } -]} - -EOT diff --git a/.evergreen/run-orchestration.sh b/.evergreen/run-orchestration.sh deleted file mode 100755 index d969aad16..000000000 --- a/.evergreen/run-orchestration.sh +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/sh -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - - -AUTH=${AUTH:-noauth} -SSL=${SSL:-nossl} -TOPOLOGY=${TOPOLOGY:-server} -STORAGE_ENGINE=${STORAGE_ENGINE} -# Set to a non-empty string to use the /disableTestCommands.json -# cluster config, eg DISABLE_TEST_COMMANDS=1 -DISABLE_TEST_COMMANDS=${DISABLE_TEST_COMMANDS} -MONGODB_VERSION=${MONGODB_VERSION:-latest} - -DL_START=$(date +%s) -DIR=$(dirname $0) -# Functions to fetch MongoDB binaries -. $DIR/download-mongodb.sh - -get_distro -if [ -z "$MONGODB_DOWNLOAD_URL" ]; then - get_mongodb_download_url_for "$DISTRO" "$MONGODB_VERSION" -else - # Even though we have the MONGODB_DOWNLOAD_URL, we still call this to get the proper EXTRACT variable - get_mongodb_download_url_for "$DISTRO" -fi -download_and_extract "$MONGODB_DOWNLOAD_URL" "$EXTRACT" - -DL_END=$(date +%s) -MO_START=$(date +%s) - -ORCHESTRATION_FILE=${ORCHESTRATION_FILE} -# If no orchestration file was specified, build up the name based on configuration parameters. -if [ -z "$ORCHESTRATION_FILE" ]; then - ORCHESTRATION_FILE="basic" - if [ "$AUTH" = "auth" ]; then - ORCHESTRATION_FILE="auth" - fi - - if [ "$SSL" != "nossl" ]; then - ORCHESTRATION_FILE="${ORCHESTRATION_FILE}-ssl" - fi - - # disableTestCommands files do not exist for different auth or ssl modes. - if [ ! -z "$DISABLE_TEST_COMMANDS" ]; then - ORCHESTRATION_FILE="disableTestCommands" - fi - - # Storage engine config files do not exist for different auth or ssl modes. - if [ ! -z "$STORAGE_ENGINE" ]; then - ORCHESTRATION_FILE="$STORAGE_ENGINE" - fi - - ORCHESTRATION_FILE="${ORCHESTRATION_FILE}.json" -fi - -TOOLS_ORCHESTRATION_FILE="$MONGO_ORCHESTRATION_HOME/configs/${TOPOLOGY}s/${ORCHESTRATION_FILE}" -CUSTOM_ORCHESTRATION_FILE="$DIR/orchestration/configs/${TOPOLOGY}s/${ORCHESTRATION_FILE}" - -if [ -f "$CUSTOM_ORCHESTRATION_FILE" ]; then - export ORCHESTRATION_FILE="$CUSTOM_ORCHESTRATION_FILE" -elif [ -f "$TOOLS_ORCHESTRATION_FILE" ]; then - export ORCHESTRATION_FILE="$TOOLS_ORCHESTRATION_FILE" -else - echo "Could not find orchestration file $ORCHESTRATION_FILE" - exit 1 -fi - -export ORCHESTRATION_URL="http://localhost:8889/v1/${TOPOLOGY}s" - -# Start mongo-orchestration -sh $DIR/start-orchestration.sh "$MONGO_ORCHESTRATION_HOME" - -pwd -if ! curl --silent --show-error --data @"$ORCHESTRATION_FILE" "$ORCHESTRATION_URL" --max-time 600 --fail -o tmp.json; then - echo Failed to start cluster, see $MONGO_ORCHESTRATION_HOME/out.log: - cat $MONGO_ORCHESTRATION_HOME/out.log - echo Failed to start cluster, see $MONGO_ORCHESTRATION_HOME/server.log: - cat $MONGO_ORCHESTRATION_HOME/server.log - exit 1 -fi -cat tmp.json -URI=$(python -c 'import sys, json; j=json.load(open("tmp.json")); print(j["mongodb_auth_uri" if "mongodb_auth_uri" in j else "mongodb_uri"])' | tr -d '\r') -echo 'MONGODB_URI: "'$URI'"' > mo-expansion.yml -echo "Cluster URI: $URI" - -MO_END=$(date +%s) -MO_ELAPSED=$(expr $MO_END - $MO_START) -DL_ELAPSED=$(expr $DL_END - $DL_START) -cat <> $DRIVERS_TOOLS/results.json -{"results": [ - { - "status": "PASS", - "test_file": "Orchestration", - "start": $MO_START, - "end": $MO_END, - "elapsed": $MO_ELAPSED - }, - { - "status": "PASS", - "test_file": "Download MongoDB", - "start": $DL_START, - "end": $DL_END, - "elapsed": $DL_ELAPSED - } -]} - -EOT diff --git a/.evergreen/start-orchestration.sh b/.evergreen/start-orchestration.sh deleted file mode 100644 index 2197f2d40..000000000 --- a/.evergreen/start-orchestration.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/bin/sh - -if [ "$#" -ne 1 ]; then - echo "$0 requires one argument: " - echo "For example: $0 /tmp/mongo-orchestration-home" - exit 1 -fi - -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - - -MONGO_ORCHESTRATION_HOME="$1" - -echo From shell `date` > $MONGO_ORCHESTRATION_HOME/server.log - -cd "$MONGO_ORCHESTRATION_HOME" -# Setup or use the existing virtualenv for mongo-orchestration. -# Prefer using Python 3 from the toolchain over the default system python. -# We may still fallback to using an old version of Python here. -# Many of the Linux distros in Evergreen ship Python 2.6 as the -# system Python. Core libraries installed by virtualenv (setuptools, -# pip, wheel) have dropped, or soon will drop, support for Python -# 2.6. Starting with version 14, virtualenv upgrades these libraries -# to the latest available on pypi when creating the virtual environment -# unless you pass --never-download. -PYTHON=$(command -v /opt/mongodbtoolchain/v2/bin/python3 || command -v python3 || command -v python) -$PYTHON -c 'import sys; print(sys.version)' -$PYTHON -c 'import ssl; print(ssl.OPENSSL_VERSION)' - -if [ -f venv/bin/activate ]; then - . venv/bin/activate -elif [ -f venv/Scripts/activate ]; then - . venv/Scripts/activate -elif $PYTHON -m virtualenv --system-site-packages --never-download venv || virtualenv --system-site-packages --never-download venv; then - if [ -f venv/bin/activate ]; then - . venv/bin/activate - elif [ -f venv/Scripts/activate ]; then - . venv/Scripts/activate - fi - # Install from github to get the latest mongo-orchestration. - pip install --upgrade 'git+git://github.com/mongodb/mongo-orchestration@master' - pip list -fi -cd - - -ORCHESTRATION_ARGUMENTS="-e default -f $MONGO_ORCHESTRATION_HOME/orchestration.config --socket-timeout-ms=60000 --bind=127.0.0.1 --enable-majority-read-concern" -if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin - ORCHESTRATION_ARGUMENTS="$ORCHESTRATION_ARGUMENTS -s wsgiref" -fi - -# Forcibly kill the process listening on port 8889, most likey a wild -# mongo-orchestration left running from a previous task. -if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin - OLD_MO_PID=$(netstat -ano | grep ':8889 .* LISTENING' | awk '{print $5}' | tr -d '[:space:]') - if [ ! -z "$OLD_MO_PID" ]; then - taskkill /F /T /PID "$OLD_MO_PID" || true - fi -else - OLD_MO_PID=$(lsof -t -i:8889 || true) - if [ ! -z "$OLD_MO_PID" ]; then - kill -9 "$OLD_MO_PID" || true - fi -fi - -mongo-orchestration $ORCHESTRATION_ARGUMENTS start > $MONGO_ORCHESTRATION_HOME/out.log 2>&1 < /dev/null & - -ls -la $MONGO_ORCHESTRATION_HOME - -sleep 5 -if ! curl http://localhost:8889/ --silent --show-error --max-time 120 --fail; then - echo Failed to start mongo-orchestration, see $MONGO_ORCHESTRATION_HOME/out.log: - cat $MONGO_ORCHESTRATION_HOME/out.log - echo Failed to start mongo-orchestration, see $MONGO_ORCHESTRATION_HOME/server.log: - cat $MONGO_ORCHESTRATION_HOME/server.log - exit 1 -fi -sleep 5 diff --git a/.evergreen/stop-orchestration.sh b/.evergreen/stop-orchestration.sh deleted file mode 100755 index 5c01d1580..000000000 --- a/.evergreen/stop-orchestration.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -set -o xtrace # Write all commands first to stderr -set -o errexit # Exit the script with error if any of the commands fail - -cd "$MONGO_ORCHESTRATION_HOME" -# source the mongo-orchestration virtualenv if it exists -if [ -f venv/bin/activate ]; then - . venv/bin/activate -elif [ -f venv/Scripts/activate ]; then - . venv/Scripts/activate -fi -mongo-orchestration stop From 2d6fce1d04aac91fdc9d5245d5be738555921842 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 9 Feb 2021 04:52:54 -0500 Subject: [PATCH 014/321] PHPLIB-612: Expect success for operations without expectError and expectResult (#807) Synced with mongodb/specifications@8a39d2253178701d6cb0ba2de1436efab8bb2a5f --- .../valid-fail/operation-failure.json | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/UnifiedSpecTests/valid-fail/operation-failure.json diff --git a/tests/UnifiedSpecTests/valid-fail/operation-failure.json b/tests/UnifiedSpecTests/valid-fail/operation-failure.json new file mode 100644 index 000000000..8f6cae152 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/operation-failure.json @@ -0,0 +1,56 @@ +{ + "description": "operation-failure", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "operation-failure" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "tests": [ + { + "description": "Unsupported command", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "unsupportedCommand", + "command": { + "unsupportedCommand": 1 + } + } + } + ] + }, + { + "description": "Unsupported query operator", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "$unsupportedQueryOperator": 1 + } + } + } + ] + } + ] +} From f915f4b6d04fa644766e782482b8a409aaef5b65 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 12 Feb 2021 11:27:56 +0100 Subject: [PATCH 015/321] Use absolute path to fix xunit result upload in Evergreen --- .evergreen/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index f2ad6a598..ac429aa47 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -164,7 +164,9 @@ functions: "upload test results": - command: attach.xunit_results params: - file: "${PROJECT_DIRECTORY}/test-results.xml" + # Uploading test results does not work when using ${PROJECT_DIRECTORY}, + # so we use an absolute path to work around this + file: "src/test-results.xml" - command: attach.results params: file_location: "${DRIVERS_TOOLS}/results.json" From a9ab2fc237e50b9df19d50e5e6a6e4db6daa7987 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 17 Feb 2021 10:34:47 +0100 Subject: [PATCH 016/321] PHPLIB-607 Support Azure and GCP keystores in FLE (#809) * Require ext-mongodb 1.10 * Install dev version of ext-mongodb * Sync spec tests * Copy spec test changes from libmongoc * Add support for GCP and Azure KMS providers * Refactor double encryption test * Refactor custom endpoint test * Test spec tests against GCP/Azure * Expose secrets as env variables * Expose CSFLE secrets in evergreen * Slim down build pipeline * Address code review feedback * Fix coding standards violation * Skip Azure FLE test due to missing certificates * Revise driver-versions axis * Add more detailed comment about re-enabling driver versions * Rename latest-stable to latest to account for varying stability * Prepare correct versions for 1.10-dev and 1.11-dev --- .evergreen/config.yml | 45 +- .github/workflows/coding-standards.yml | 9 +- .github/workflows/tests.yml | 16 +- composer.json | 2 +- .../ClientSideEncryptionSpecTest.php | 535 +- tests/SpecTests/Context.php | 44 +- .../corpus/corpus-encrypted.json | 3662 ++++++++++++- .../corpus/corpus-key-aws.json | 18 +- .../corpus/corpus-key-azure.json | 33 + .../corpus/corpus-key-gcp.json | 35 + .../corpus/corpus-key-local.json | 14 +- .../corpus/corpus-schema.json | 3254 +++++++++++- .../client-side-encryption/corpus/corpus.json | 4580 ++++++++++++++++- .../external/external-key.json | 14 +- .../external/external-schema.json | 6 +- .../limits/limits-doc.json | 198 +- .../limits/limits-key.json | 14 +- .../limits/limits-schema.json | 800 +-- .../tests/azureKMS.json | 223 + .../client-side-encryption/tests/gcpKMS.json | 224 + .../tests/maxWireVersion.json | 3 + 21 files changed, 12569 insertions(+), 1160 deletions(-) create mode 100644 tests/SpecTests/client-side-encryption/corpus/corpus-key-azure.json create mode 100644 tests/SpecTests/client-side-encryption/corpus/corpus-key-gcp.json create mode 100644 tests/SpecTests/client-side-encryption/tests/azureKMS.json create mode 100644 tests/SpecTests/client-side-encryption/tests/gcpKMS.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index ac429aa47..055783e5f 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -207,6 +207,13 @@ functions: working_dir: "src" script: | ${PREPARE_SHELL} + export AWS_ACCESS_KEY_ID="${client_side_encryption_aws_access_key_id}" + export AWS_SECRET_ACCESS_KEY="${client_side_encryption_aws_secret_access_key}" + export AZURE_TENANT_ID="${client_side_encryption_azure_tenant_id}" + export AZURE_CLIENT_ID="${client_side_encryption_azure_client_id}" + export AZURE_CLIENT_SECRET="${client_side_encryption_azure_client_secret}" + export GCP_EMAIL="${client_side_encryption_gcp_email}" + export GCP_PRIVATEKEY="${client_side_encryption_gcp_privatekey}" PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run atlas data lake test": @@ -436,22 +443,27 @@ axes: - id: driver-versions display_name: Driver Version values: - - id: "lowest-supported" - display_name: "1.9.0" - variables: - DRIVER_VERSION: "1.9.0" - - id: "latest-stable" - display_name: "1.9-stable" - variables: - DRIVER_VERSION: "stable" - - id: "1.9-dev" - display_name: "1.9-dev" - variables: - DRIVER_BRANCH: "v1.9" - - id: "latest-dev" + # TODO: this axis can be cleaned up as we move towards a 1.10 release: + # * lowest-supported can be enabled once a 1.10 patch release has been tagged + # * latest-stable can be updated when we start tagging 1.10 releases (even beta) + # * 1.10-dev can be enabled once 1.10 has been branched + # * latest-dev can be enabled once 1.10 has been branched +# - id: "lowest-supported" +# display_name: "1.10-dev (master)" +# variables: +# DRIVER_BRANCH: "master" + - id: "latest" display_name: "1.10-dev (master)" variables: DRIVER_BRANCH: "master" +# - id: "1.10-dev" +# display_name: "1.10-dev" +# variables: +# DRIVER_BRANCH: "v1.10" +# - id: "latest-dev" +# display_name: "1.11-dev (master)" +# variables: +# DRIVER_BRANCH: "master" - id: os-php7 display_name: OS @@ -541,7 +553,7 @@ buildvariants: # Tests all PHP versions on all operating systems. # Only tests against latest MongoDB and ext-mongodb versions - matrix_name: "test-php-versions" - matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest-stable" } + matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest" } exclude_spec: # rhel71-power8 fails due to not reaching pecl - { "os-php7": "rhel71-power8", "php-versions": "*", edge-versions: "*", "driver-versions": "*" } @@ -567,7 +579,7 @@ buildvariants: # Only tests on Ubuntu 18.04, with latest stable PHP and driver versions # Tests against various topologies - matrix_name: "test-mongodb-versions" - matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest-stable" } + matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest" } display_name: "MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" @@ -576,8 +588,9 @@ buildvariants: # Tests oldest supported version # Enables --prefer-lowest for composer to test oldest dependencies against all server versions +# TODO: driver-versions can be changed back to lowest-supported when that version is enabled in the axis - matrix_name: "test-dependencies" - matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "lowest-supported" } + matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "latest" } display_name: "Dependencies: ${dependencies}, MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 70be76d05..7ba3c8a21 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -19,6 +19,8 @@ jobs: matrix: php-version: - "7.4" + driver-version: + - "mongodb/mongo-php-driver@master" steps: - name: "Checkout" @@ -29,7 +31,7 @@ jobs: uses: shivammathur/cache-extensions@v1 with: php-version: ${{ matrix.php-version }} - extensions: "mongodb" + extensions: "mongodb-${{ matrix.driver-version }}" key: "extcache-v1" - name: Cache extensions @@ -40,10 +42,11 @@ jobs: restore-keys: ${{ steps.extcache.outputs.key }} - name: "Install PHP" - uses: "shivammathur/setup-php@v2" + # Todo: switch to @v2 once a tag has been created + uses: "shivammathur/setup-php@develop" with: coverage: "none" - extensions: "mongodb" + extensions: "mongodb-${{ matrix.driver-version }}" php-version: "${{ matrix.php-version }}" tools: "cs2pr" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6287923f8..5e1a46d2a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,19 +26,19 @@ jobs: mongodb-version: - "4.4" driver-version: - - "stable" + - "mongodb/mongo-php-driver@master" topology: - "server" include: - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "replica_set" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "sharded_cluster" steps: @@ -69,7 +69,8 @@ jobs: restore-keys: ${{ steps.extcache.outputs.key }} - name: "Install PHP" - uses: "shivammathur/setup-php@v2" + # Todo: switch to @v2 once a tag has been created + uses: "shivammathur/setup-php@develop" with: php-version: "${{ matrix.php-version }}" tools: "pecl" @@ -95,3 +96,10 @@ jobs: env: SYMFONY_DEPRECATIONS_HELPER: 999999 MONGODB_URI: ${{ steps.setup-mongodb.outputs.cluster-uri }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + GCP_EMAIL: ${{ secrets.GCP_EMAIL }} + GCP_PRIVATE_KEY: ${{ secrets.GCP_PRIVATE_KEY }} diff --git a/composer.json b/composer.json index 4e2faa080..2953ebba7 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.0 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.9.0", + "ext-mongodb": "^1.10.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index f2edd7f6b..a200dc8d7 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -26,6 +26,7 @@ use function basename; use function file_get_contents; use function glob; +use function in_array; use function iterator_to_array; use function json_decode; use function sprintf; @@ -167,7 +168,7 @@ public function provideTests() * * @dataProvider dataKeyProvider */ - public function testDataKeyAndDoubleEncryption(Closure $test) + public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey) { $client = new Client(static::getUri()); @@ -178,6 +179,8 @@ public function testDataKeyAndDoubleEncryption(Closure $test) 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials(), + 'gcp' => Context::getGCPCredentials(), 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], ], ]; @@ -203,104 +206,86 @@ public function testDataKeyAndDoubleEncryption(Closure $test) $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncryption = $clientEncrypted->createClientEncryption($encryptionOpts); - $test($clientEncryption, $client, $clientEncrypted, $this); + $commands = []; + + $dataKeyId = null; + $keyAltName = $providerName . '_altname'; + + (new CommandObserver())->observe( + function () use ($clientEncryption, &$dataKeyId, $keyAltName, $providerName, $masterKey) { + $keyData = ['keyAltNames' => [$keyAltName]]; + if ($masterKey !== null) { + $keyData['masterKey'] = $masterKey; + } + + $dataKeyId = $clientEncryption->createDataKey($providerName, $keyData); + }, + function ($command) use (&$commands) { + $commands[] = $command; + } + ); + + $this->assertInstanceOf(Binary::class, $dataKeyId); + $this->assertSame(Binary::TYPE_UUID, $dataKeyId->getType()); + + $this->assertCount(2, $commands); + $insert = $commands[1]['started']; + $this->assertSame('insert', $insert->getCommandName()); + $this->assertSame(WriteConcern::MAJORITY, $insert->getCommand()->writeConcern->w); + + $keys = $client->selectCollection('keyvault', 'datakeys')->find(['_id' => $dataKeyId]); + $keys = iterator_to_array($keys); + $this->assertCount(1, $keys); + + $key = $keys[0]; + $this->assertNotNull($key); + $this->assertSame($providerName, $key['masterKey']['provider']); + + $encrypted = $clientEncryption->encrypt('hello ' . $providerName, ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $dataKeyId]); + $this->assertInstanceOf(Binary::class, $encrypted); + $this->assertSame(Binary::TYPE_ENCRYPTED, $encrypted->getType()); + + $clientEncrypted->selectCollection('db', 'coll')->insertOne(['_id' => 'local', 'value' => $encrypted]); + $hello = $clientEncrypted->selectCollection('db', 'coll')->findOne(['_id' => 'local']); + $this->assertNotNull($hello); + $this->assertSame('hello ' . $providerName, $hello['value']); + + $encryptedAltName = $clientEncryption->encrypt('hello ' . $providerName, ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyAltName' => $keyAltName]); + $this->assertEquals($encrypted, $encryptedAltName); + + $this->expectException(BulkWriteException::class); + $clientEncrypted->selectCollection('db', 'coll')->insertOne(['encrypted_placeholder' => $encrypted]); } public static function dataKeyProvider() { return [ 'local' => [ - static function (ClientEncryption $clientEncryption, Client $client, Client $clientEncrypted, self $test) { - $commands = []; - - $localDatakeyId = null; - - (new CommandObserver())->observe( - function () use ($clientEncryption, &$localDatakeyId) { - $localDatakeyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['local_altname']]); - }, - function ($command) use (&$commands) { - $commands[] = $command; - } - ); - - $test->assertInstanceOf(Binary::class, $localDatakeyId); - $test->assertSame(Binary::TYPE_UUID, $localDatakeyId->getType()); - - $test->assertCount(2, $commands); - $insert = $commands[1]['started']; - $test->assertSame('insert', $insert->getCommandName()); - $test->assertSame(WriteConcern::MAJORITY, $insert->getCommand()->writeConcern->w); - - $keys = $client->selectCollection('keyvault', 'datakeys')->find(['_id' => $localDatakeyId]); - $keys = iterator_to_array($keys); - $test->assertCount(1, $keys); - - $key = $keys[0]; - $test->assertNotNull($key); - $test->assertSame('local', $key['masterKey']['provider']); - - $localEncrypted = $clientEncryption->encrypt('hello local', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $localDatakeyId]); - $test->assertInstanceOf(Binary::class, $localEncrypted); - $test->assertSame(Binary::TYPE_ENCRYPTED, $localEncrypted->getType()); - - $clientEncrypted->selectCollection('db', 'coll')->insertOne(['_id' => 'local', 'value' => $localEncrypted]); - $helloLocal = $clientEncrypted->selectCollection('db', 'coll')->findOne(['_id' => 'local']); - $test->assertNotNull($helloLocal); - $test->assertSame('hello local', $helloLocal['value']); - - $localEncryptedAltName = $clientEncryption->encrypt('hello local', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyAltName' => 'local_altname']); - $test->assertEquals($localEncrypted, $localEncryptedAltName); - - $test->expectException(BulkWriteException::class); - $clientEncrypted->selectCollection('db', 'coll')->insertOne(['encrypted_placeholder' => $localEncrypted]); - }, + 'providerName' => 'local', + 'masterKey' => null, ], 'aws' => [ - static function (ClientEncryption $clientEncryption, Client $client, Client $clientEncrypted, self $test) { - $commands = []; - $awsDatakeyId = null; - - (new CommandObserver())->observe( - function () use ($clientEncryption, &$awsDatakeyId) { - $awsDatakeyId = $clientEncryption->createDataKey('aws', ['keyAltNames' => ['aws_altname'], 'masterKey' => ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0']]); - }, - function ($command) use (&$commands) { - $commands[] = $command; - } - ); - - $test->assertInstanceOf(Binary::class, $awsDatakeyId); - $test->assertSame(Binary::TYPE_UUID, $awsDatakeyId->getType()); - - $test->assertCount(2, $commands); - $insert = $commands[1]['started']; - $test->assertSame('insert', $insert->getCommandName()); - $test->assertSame(WriteConcern::MAJORITY, $insert->getCommand()->writeConcern->w); - - $keys = $client->selectCollection('keyvault', 'datakeys')->find(['_id' => $awsDatakeyId]); - $keys = iterator_to_array($keys); - $test->assertCount(1, $keys); - - $key = $keys[0]; - $test->assertNotNull($key); - $test->assertSame('aws', $key['masterKey']['provider']); - - $awsEncrypted = $clientEncryption->encrypt('hello aws', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $awsDatakeyId]); - $test->assertInstanceOf(Binary::class, $awsEncrypted); - $test->assertSame(Binary::TYPE_ENCRYPTED, $awsEncrypted->getType()); - - $clientEncrypted->selectCollection('db', 'coll')->insertOne(['_id' => 'aws', 'value' => $awsEncrypted]); - $helloAws = $clientEncrypted->selectCollection('db', 'coll')->findOne(['_id' => 'aws']); - $test->assertNotNull($helloAws); - $test->assertSame('hello aws', $helloAws['value']); - - $awsEncryptedAltName = $clientEncryption->encrypt('hello aws', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyAltName' => 'aws_altname']); - $test->assertEquals($awsEncrypted, $awsEncryptedAltName); - - $test->expectException(BulkWriteException::class); - $clientEncrypted->selectCollection('db', 'coll')->insertOne(['encrypted_placeholder' => $awsEncrypted]); - }, + 'providerName' => 'aws', + 'masterKey' => [ + 'region' => 'us-east-1', + 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + ], + ], + 'azure' => [ + 'providerName' => 'azure', + 'masterKey' => [ + 'keyVaultEndpoint' => 'key-vault-csfle.vault.azure.net', + 'keyName' => 'key-name-csfle', + ], + ], + 'gcp' => [ + 'providerName' => 'gcp', + 'masterKey' => [ + 'projectId' => 'devprod-drivers', + 'location' => 'global', + 'keyRing' => 'key-ring-csfle', + 'keyName' => 'key-name-csfle', + ], ], ]; } @@ -371,85 +356,85 @@ public function testExternalKeyVault($withExternalKeyVault) public static function provideBSONSizeLimitsAndBatchSplittingTests() { - yield [static function (self $test, Collection $collection) { - // Test 1 - $collection->insertOne(['_id' => 'over_2mib_under_16mib', 'unencrypted' => str_repeat('a', 2097152)]); - $test->assertCollectionCount($collection->getNamespace(), 1); - }, + yield 'Test 1' => [ + static function (self $test, Collection $collection) { + $collection->insertOne(['_id' => 'over_2mib_under_16mib', 'unencrypted' => str_repeat('a', 2097152)]); + $test->assertCollectionCount($collection->getNamespace(), 1); + }, ]; - yield [static function (self $test, Collection $collection, array $document) { - // Test 2 - $collection->insertOne( - ['_id' => 'encryption_exceeds_2mib', 'unencrypted' => str_repeat('a', 2097152 - 2000)] + $document - ); - $test->assertCollectionCount($collection->getNamespace(), 1); - }, + yield 'Test 2' => [ + static function (self $test, Collection $collection, array $document) { + $collection->insertOne( + ['_id' => 'encryption_exceeds_2mib', 'unencrypted' => str_repeat('a', 2097152 - 2000)] + $document + ); + $test->assertCollectionCount($collection->getNamespace(), 1); + }, ]; - yield [static function (self $test, Collection $collection) { - // Test 3 - $commands = []; - (new CommandObserver())->observe( - function () use ($collection) { - $collection->insertMany([ - ['_id' => 'over_2mib_1', 'unencrypted' => str_repeat('a', 2097152)], - ['_id' => 'over_2mib_2', 'unencrypted' => str_repeat('a', 2097152)], - ]); - }, - function ($command) use (&$commands) { - $commands[] = $command; + yield 'Test 3' => [ + static function (self $test, Collection $collection) { + $commands = []; + (new CommandObserver())->observe( + function () use ($collection) { + $collection->insertMany([ + ['_id' => 'over_2mib_1', 'unencrypted' => str_repeat('a', 2097152)], + ['_id' => 'over_2mib_2', 'unencrypted' => str_repeat('a', 2097152)], + ]); + }, + function ($command) use (&$commands) { + $commands[] = $command; + } + ); + + $test->assertCount(2, $commands); + foreach ($commands as $command) { + $test->assertSame('insert', $command['started']->getCommandName()); } - ); - - $test->assertCount(2, $commands); - foreach ($commands as $command) { - $test->assertSame('insert', $command['started']->getCommandName()); - } - }, + }, ]; - yield [static function (self $test, Collection $collection, array $document) { - // Test 4 - $commands = []; - (new CommandObserver())->observe( - function () use ($collection, $document) { - $collection->insertMany([ - [ - '_id' => 'encryption_exceeds_2mib_1', - 'unencrypted' => str_repeat('a', 2097152 - 2000), - ] + $document, - [ - '_id' => 'encryption_exceeds_2mib_2', - 'unencrypted' => str_repeat('a', 2097152 - 2000), - ] + $document, - ]); - }, - function ($command) use (&$commands) { - $commands[] = $command; + yield 'Test 4' => [ + static function (self $test, Collection $collection, array $document) { + $commands = []; + (new CommandObserver())->observe( + function () use ($collection, $document) { + $collection->insertMany([ + [ + '_id' => 'encryption_exceeds_2mib_1', + 'unencrypted' => str_repeat('a', 2097152 - 2000), + ] + $document, + [ + '_id' => 'encryption_exceeds_2mib_2', + 'unencrypted' => str_repeat('a', 2097152 - 2000), + ] + $document, + ]); + }, + function ($command) use (&$commands) { + $commands[] = $command; + } + ); + + $test->assertCount(2, $commands); + foreach ($commands as $command) { + $test->assertSame('insert', $command['started']->getCommandName()); } - ); - - $test->assertCount(2, $commands); - foreach ($commands as $command) { - $test->assertSame('insert', $command['started']->getCommandName()); - } - }, + }, ]; - yield [static function (self $test, Collection $collection) { - // Test 5 - $collection->insertOne(['_id' => 'under_16mib', 'unencrypted' => str_repeat('a', 16777216 - 2000)]); - $test->assertCollectionCount($collection->getNamespace(), 1); - }, + yield 'Test 5' => [ + static function (self $test, Collection $collection) { + $collection->insertOne(['_id' => 'under_16mib', 'unencrypted' => str_repeat('a', 16777216 - 2000)]); + $test->assertCollectionCount($collection->getNamespace(), 1); + }, ]; - yield [static function (self $test, Collection $collection, array $document) { - // Test 6 - $test->expectException(BulkWriteException::class); - $test->expectExceptionMessageMatches('#object to insert too large#'); - $collection->insertOne(['_id' => 'encryption_exceeds_16mib', 'unencrypted' => str_repeat('a', 16777216 - 2000)] + $document); - }, + yield 'Test 6' => [ + static function (self $test, Collection $collection, array $document) { + $test->expectException(BulkWriteException::class); + $test->expectExceptionMessageMatches('#object to insert too large#'); + $collection->insertOne(['_id' => 'encryption_exceeds_16mib', 'unencrypted' => str_repeat('a', 16777216 - 2000)] + $document); + }, ]; } @@ -539,12 +524,16 @@ public function testCorpus($schemaMap = true) $client->selectCollection('keyvault', 'datakeys')->insertMany([ $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-local.json')), $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-aws.json')), + $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-azure.json')), + $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-gcp.json')), ]); $encryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials(), + 'gcp' => Context::getGCPCredentials(), 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], ], ]; @@ -565,80 +554,180 @@ public function testCorpus($schemaMap = true) $collection = $clientEncrypted->selectCollection('db', 'coll'); + $unpreparedFieldNames = [ + '_id', + 'altname_aws', + 'altname_azure', + 'altname_gcp', + 'altname_local', + ]; + foreach ($corpus as $fieldName => $data) { - switch ($fieldName) { - case '_id': - case 'altname_aws': - case 'altname_local': - $corpusCopied[$fieldName] = $data; - break; - - default: - $corpusCopied[$fieldName] = $this->prepareCorpusData($data, $clientEncryption); + if (in_array($fieldName, $unpreparedFieldNames, true)) { + $corpusCopied[$fieldName] = $data; + continue; } + + $corpusCopied[$fieldName] = $this->prepareCorpusData($fieldName, $data, $clientEncryption); } $collection->insertOne($corpusCopied); $corpusDecrypted = $collection->findOne(['_id' => 'client_side_encryption_corpus']); $this->assertDocumentsMatch($corpus, $corpusDecrypted); + + $corpusEncryptedExpected = (array) $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-encrypted.json')); + $corpusEncryptedActual = $client->selectCollection('db', 'coll')->findOne(['_id' => 'client_side_encryption_corpus'], ['typeMap' => ['root' => 'array', 'document' => stdClass::class, 'array' => 'array']]); + + foreach ($corpusEncryptedExpected as $fieldName => $expectedData) { + if (in_array($fieldName, $unpreparedFieldNames, true)) { + continue; + } + + $actualData = $corpusEncryptedActual[$fieldName]; + + if ($expectedData->algo === 'det') { + $this->assertEquals($expectedData->value, $actualData->value, 'Value for field ' . $fieldName . ' does not match expected value.'); + } + + if ($expectedData->allowed) { + if ($expectedData->algo === 'rand') { + $this->assertNotEquals($expectedData->value, $actualData->value, 'Value for field ' . $fieldName . ' does not differ from expected value.'); + } + + $this->assertEquals( + $clientEncryption->decrypt($expectedData->value), + $clientEncryption->decrypt($actualData->value), + 'Decrypted value for field ' . $fieldName . ' does not match.' + ); + } else { + $this->assertEquals($corpus[$fieldName]->value, $actualData->value, 'Value for field ' . $fieldName . ' does not match original value.'); + } + } } /** * Prose test: Custom Endpoint + * + * @dataProvider customEndpointProvider */ - public function testCustomEndpoint() + public function testCustomEndpoint(Closure $test) { - // Test 1 $client = new Client(static::getUri()); - $encryptionOpts = [ + $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => 'login.microsoftonline.com:443'], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => 'oauth2.googleapis.com:443'], ], + ]); + + $clientEncryptionInvalid = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => 'example.com:443'], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => 'example.com:443'], + ], + ]); + + $test($this, $clientEncryption, $clientEncryptionInvalid); + } + + public static function customEndpointProvider() + { + $awsMasterKey = ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0']; + $azureMasterKey = ['keyVaultEndpoint' => 'key-vault-csfle.vault.azure.net', 'keyName' => 'key-name-csfle']; + $gcpMasterKey = [ + 'projectId' => 'devprod-drivers', + 'location' => 'global', + 'keyRing' => 'key-ring-csfle', + 'keyName' => 'key-name-csfle', + 'endpoint' => 'cloudkms.googleapis.com:443', ]; - $clientEncryption = $client->createClientEncryption($encryptionOpts); + yield 'Test 1' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + }, + ]; - // Test 2 - $masterKeyConfig = ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0']; - $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $masterKeyConfig]); - $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); - $this->assertSame('test', $clientEncryption->decrypt($encrypted)); + yield 'Test 2' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-1.amazonaws.com']]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + }, + ]; - // Test 3 - $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $masterKeyConfig + ['endpoint' => 'kms.us-east-1.amazonaws.com']]); - $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); - $this->assertSame('test', $clientEncryption->decrypt($encrypted)); + yield 'Test 3' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + [ 'endpoint' => 'kms.us-east-1.amazonaws.com:443']]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + }, + ]; - // Test 4 - $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $masterKeyConfig + [ 'endpoint' => 'kms.us-east-1.amazonaws.com:443']]); - $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); - $this->assertSame('test', $clientEncryption->decrypt($encrypted)); + yield 'Test 4' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + $test->expectException(ConnectionException::class); + $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-1.amazonaws.com:12345']]); + }, + ]; - // Test 5 - try { - $clientEncryption->createDataKey('aws', ['masterKey' => $masterKeyConfig + [ 'endpoint' => 'kms.us-east-1.amazonaws.com:12345']]); - $this->fail('Expected exception to be thrown'); - } catch (ConnectionException $e) { - } + yield 'Test 5' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#us-east-1#'); + $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-2.amazonaws.com']]); + }, + ]; - // Test 6 - try { - $clientEncryption->createDataKey('aws', ['masterKey' => $masterKeyConfig + [ 'endpoint' => 'kms.us-east-2.amazonaws.com']]); - $this->fail('Expected exception to be thrown'); - } catch (RuntimeException $e) { - $this->assertStringContainsString('us-east-1', $e->getMessage()); - } + yield 'Test 6' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#parse error#'); + $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'example.com']]); + }, + ]; - // Test 7 - try { - $clientEncryption->createDataKey('aws', ['masterKey' => $masterKeyConfig + [ 'endpoint' => 'example.com']]); - $this->fail('Expected exception to be thrown'); - } catch (RuntimeException $e) { - $this->assertStringContainsString('parse error', $e->getMessage()); - } + yield 'Test 7' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($azureMasterKey) { + $keyId = $clientEncryption->createDataKey('azure', ['masterKey' => $azureMasterKey]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#parse error#'); + $clientEncryptionInvalid->createDataKey('azure', ['masterKey' => $azureMasterKey]); + }, + ]; + + yield 'Test 8' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey) { + $keyId = $clientEncryption->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#parse error#'); + $clientEncryptionInvalid->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); + }, + ]; + + yield 'Test 9' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey) { + $masterKey = $gcpMasterKey; + $masterKey['endpoint'] = 'example.com:443'; + + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#Invalid KMS response#'); + $clientEncryption->createDataKey('gcp', ['masterKey' => $masterKey]); + }, + ]; } /** @@ -732,20 +821,41 @@ private function createTestCollection($jsonSchema) $operation->execute($this->getPrimaryServer()); } - private function encryptCorpusValue(stdClass $data, ClientEncryption $clientEncryption) + private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEncryption $clientEncryption) { $encryptionOptions = [ 'algorithm' => $data->algo === 'rand' ? ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_RANDOM : ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, ]; + switch ($data->kms) { + case 'local': + $keyId = 'LOCALAAAAAAAAAAAAAAAAA=='; + $keyAltName = 'local'; + break; + case 'aws': + $keyId = 'AWSAAAAAAAAAAAAAAAAAAA=='; + $keyAltName = 'aws'; + break; + case 'azure': + $keyId = 'AZUREAAAAAAAAAAAAAAAAA=='; + $keyAltName = 'azure'; + break; + case 'gcp': + $keyId = 'GCPAAAAAAAAAAAAAAAAAAA=='; + $keyAltName = 'gcp'; + break; + + default: + throw new UnexpectedValueException('Unexpected KMS "%s"', $data->kms); + } + switch ($data->identifier) { case 'id': - $keyId = $data->kms === 'local' ? 'LOCALAAAAAAAAAAAAAAAAA==' : 'AWSAAAAAAAAAAAAAAAAAAA=='; $encryptionOptions['keyId'] = new Binary(base64_decode($keyId), 4); break; case 'altname': - $encryptionOptions['keyAltName'] = $data->kms === 'local' ? 'local' : 'aws'; + $encryptionOptions['keyAltName'] = $keyAltName; break; default: @@ -753,7 +863,12 @@ private function encryptCorpusValue(stdClass $data, ClientEncryption $clientEncr } if ($data->allowed) { - $encrypted = $clientEncryption->encrypt($this->craftInt64($data), $encryptionOptions); + try { + $encrypted = $clientEncryption->encrypt($this->craftInt64($data), $encryptionOptions); + } catch (EncryptionException $e) { + $this->fail('Could not encrypt value for field ' . $fieldName . ': ' . $e->getMessage()); + } + $this->assertEquals($data->value, $clientEncryption->decrypt($encrypted)); return $encrypted; @@ -782,7 +897,7 @@ private function insertKeyVaultData(array $keyVaultData = null) return; } - private function prepareCorpusData(stdClass $data, ClientEncryption $clientEncryption) + private function prepareCorpusData(string $fieldName, stdClass $data, ClientEncryption $clientEncryption) { if ($data->method === 'auto') { $data->value = $this->craftInt64($data); @@ -791,7 +906,7 @@ private function prepareCorpusData(stdClass $data, ClientEncryption $clientEncry } $returnData = clone $data; - $returnData->value = $this->encryptCorpusValue($data, $clientEncryption); + $returnData->value = $this->encryptCorpusValue($fieldName, $data, $clientEncryption); return $data->allowed ? $returnData : $data; } diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index dde7304d7..1d0e6bd8c 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -8,7 +8,7 @@ use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; -use PHPUnit\Framework\SkippedTestError; +use PHPUnit\Framework\Assert; use stdClass; use function array_diff_key; use function array_keys; @@ -118,6 +118,14 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ if (isset($autoEncryptionOptions['kmsProviders']->aws)) { $autoEncryptionOptions['kmsProviders']->aws = self::getAWSCredentials(); } + + if (isset($autoEncryptionOptions['kmsProviders']->azure)) { + $autoEncryptionOptions['kmsProviders']->azure = self::getAzureCredentials(); + } + + if (isset($autoEncryptionOptions['kmsProviders']->gcp)) { + $autoEncryptionOptions['kmsProviders']->gcp = self::getGCPCredentials(); + } } if (isset($test->outcome->collection->name)) { @@ -243,15 +251,10 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti return $o; } - /** - * @return array - * - * @throws SkippedTestError - */ - public static function getAWSCredentials() + public static function getAWSCredentials() : array { if (! getenv('AWS_ACCESS_KEY_ID') || ! getenv('AWS_SECRET_ACCESS_KEY')) { - throw new SkippedTestError('Please configure AWS credentials to use AWS KMS provider.'); + Assert::markTestSkipped('Please configure AWS credentials to use AWS KMS provider.'); } return [ @@ -260,6 +263,31 @@ public static function getAWSCredentials() ]; } + public static function getAzureCredentials() : array + { + if (! getenv('AZURE_TENANT_ID') || ! getenv('AZURE_CLIENT_ID') || ! getenv('AZURE_CLIENT_SECRET')) { + Assert::markTestSkipped('Please configure Azure credentials to use Azure KMS provider.'); + } + + return [ + 'tenantId' => getenv('AZURE_TENANT_ID'), + 'clientId' => getenv('AZURE_CLIENT_ID'), + 'clientSecret' => getenv('AZURE_CLIENT_SECRET'), + ]; + } + + public static function getGCPCredentials() : array + { + if (! getenv('GCP_EMAIL') || ! getenv('GCP_PRIVATE_KEY')) { + Assert::markTestSkipped('Please configure GCP credentials to use GCP KMS provider.'); + } + + return [ + 'email' => getenv('GCP_EMAIL'), + 'privateKey' => getenv('GCP_PRIVATE_KEY'), + ]; + } + /** * @return Client */ diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json b/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json index 998b058b0..a11682688 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json @@ -4021,5 +4021,3665 @@ "subType": "06" } } + }, + "azure_double_rand_auto_id": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAB0S2kOZe54q6iZqeTLndkX+kehTKtb30jTP7FS+Zx+cxhFs626OrGY+jrH41cLfroCccacyNHUZFRinfqZPNOyw==", + "subType": "06" + } + } + }, + "azure_double_rand_auto_altname": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAABYViH7PLjCIdmTibW9dGCJADwXx2dRSMYxEmulPu89clAoeLDa8pwJ7YxLFQCcTGmZRfmp58dDDAzV8tyyE8QMg==", + "subType": "06" + } + } + }, + "azure_double_rand_explicit_id": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAABeRahSj4pniBp0rLIEZE8MdeyiIKcYuTZiuGzGiXbFbntEPow88DFHIBSxbMGR7p/8jCpPL+GqBwFkPkafXbMzg==", + "subType": "06" + } + } + }, + "azure_double_rand_explicit_altname": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAABdaa3vKtO4cAEUjYJfOPl1KbbgeWtphfUuJd6MxR9VReNSf1jc+kONwmkPVQs2WyZ1n+TSQMGRoBp1nHRttDdTg==", + "subType": "06" + } + } + }, + "azure_double_det_explicit_id": { + "kms": "azure", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "azure_double_det_explicit_altname": { + "kms": "azure", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "azure_string_rand_auto_id": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAACeoztcDg9oZ7ixHinReWQTrAumpsfyb0E1s3BGOFHgBCi1tW79CEXfqN8riFRc1YeRTlN4k5ShgHaBWBlax+XoQ==", + "subType": "06" + } + } + }, + "azure_string_rand_auto_altname": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAACov9cXQvDHeKOS5Gxcxa8vdAcTsTXDYgUucGzsCyh4TnTWKGQEVk3DHndUXX569TKCjq5QsC//oWEwweCn1nZ4g==", + "subType": "06" + } + } + }, + "azure_string_rand_explicit_id": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAACKU5qTdMdO0buQ/37ZRANUAAafcsoNMOTxJsDOfkqUb+/kRgM1ePlwVvk4EJiAGhJ/4SEmEOpwv05TT3PxGur2Q==", + "subType": "06" + } + } + }, + "azure_string_rand_explicit_altname": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAACX/ODKGHUyAKxoJ/c/3lEDBTc+eP/VS8OHrLhYoP96McpnFSgYi5jfUwvrFYa715fkass4N0nAHE6TzoGTYyk6Q==", + "subType": "06" + } + } + }, + "azure_string_det_auto_id": { + "kms": "azure", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAACmVI7YK4JLOzutEdQ79he817Vk5EDP/3hXwOlGmERZCtp8J8HcqClhV+pyvRLGbwmlh12fbSs9nEp7mrobQm9wA==", + "subType": "06" + } + } + }, + "azure_string_det_explicit_id": { + "kms": "azure", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAACmVI7YK4JLOzutEdQ79he817Vk5EDP/3hXwOlGmERZCtp8J8HcqClhV+pyvRLGbwmlh12fbSs9nEp7mrobQm9wA==", + "subType": "06" + } + } + }, + "azure_string_det_explicit_altname": { + "kms": "azure", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAACmVI7YK4JLOzutEdQ79he817Vk5EDP/3hXwOlGmERZCtp8J8HcqClhV+pyvRLGbwmlh12fbSs9nEp7mrobQm9wA==", + "subType": "06" + } + } + }, + "azure_object_rand_auto_id": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAADWkZMsfCo4dOPMH1RXC7GkZFt1RCjJf0vaLDA09ih1Jl47SOetZELQ7B1TQjRQitktzrfD43jk8Fn4J5ZYZu1qQ==", + "subType": "06" + } + } + }, + "azure_object_rand_auto_altname": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAADJFMymfstltZP1oAqj4bgbCk8uLGtCd12eLqvSq0ZO+JDvls7PAovwmoWwigHunP8BBXT8sLydK+jn1sHfnhrlw==", + "subType": "06" + } + } + }, + "azure_object_rand_explicit_id": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAADCen+XrLYKg7gIVubVfdbQwuJ0mFHxhSUUyyBWj4RCeLeLUYXckboPGixXWB9XdwcOnInfF9u6qvktY67GtYASQ==", + "subType": "06" + } + } + }, + "azure_object_rand_explicit_altname": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAADnUyp/7eLmxxxOdsP+mNuJABK4PQoKFWDAY7lDrH6MYa03ryASOihPZWYZWXZLrbAf7cQQhElEkKqKwY8+NXgqg==", + "subType": "06" + } + } + }, + "azure_object_det_explicit_id": { + "kms": "azure", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_object_det_explicit_altname": { + "kms": "azure", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_array_rand_auto_id": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAEtk14WyoatZcNPlg3y/XJNsBt6neFJeQwR06B9rMGV58oIsmeE5zMtUOBYTgzlnwyKpqI/XVAg8s1VxvsrvGCyLVPwGVyDztwtMgVSW6QM3s=", + "subType": "06" + } + } + }, + "azure_array_rand_auto_altname": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAERTO63J4Nj1BpFlqVduA2IrAiGoV4jEOH3FnFgx7ZP7da/YBmLX/bc1EqdpC8v4faHxp74iU0xAB0yW4WgySDX7rriL5cw9sMpqgLRaBxGug=", + "subType": "06" + } + } + }, + "azure_array_rand_explicit_id": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAEs09qQdNVwh+KFqKPREQkw0XFdRNHAvjYJzs5MDE9+QxvtKlmVKSK3wkxDdCrcH4r7ePV2nCy2h1IHYqaDnnt4s5dSawI2l88iTT+bBcCSrU=", + "subType": "06" + } + } + }, + "azure_array_rand_explicit_altname": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAEaQ/YL50up4YIMJuVJSiAP06IQ+YjdKLIfkN/prbOZMiXErcD1Vq1hwGhfGdpEsLVu8E7IhJb4wakVC/2dLZoRP95az6HqRRauNNZAIQMKfY=", + "subType": "06" + } + } + }, + "azure_array_det_explicit_id": { + "kms": "azure", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_array_det_explicit_altname": { + "kms": "azure", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_binData=00_rand_auto_id": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFl/leuLAHf1p6aRKHdFyN9FM6MW2XzBemql2xQgqkwJ6YOQXW6Pu/aI1scXVOrvrSu3+wBvByjHu++1AqFgzZRQ==", + "subType": "06" + } + } + }, + "azure_binData=00_rand_auto_altname": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAF4Nq/LwyufT/mx0LtFSkupNHTuyjbr4yUy1N5/37XhkpqZ1e4sWCHGNaTDEm5+cvdnbqZ/MMkBv855dc8N7vnGA==", + "subType": "06" + } + } + }, + "azure_binData=00_rand_explicit_id": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFv1Kbv54uXJ76Ih63vtmszQtzkXqDlv8LDCFO3sjzu70+tgRXOhLm3J8uZpwoiNkgM6oNLn0en7tnEekYB9++CA==", + "subType": "06" + } + } + }, + "azure_binData=00_rand_explicit_altname": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFgcYC1n7cGGXpv0qf1Kb8t9y/6kbhscGt2QJkQpAiqadFPPYDU/wwaKdDz94NpAHMZizUbhf9tvZ3UXl1bozhDA==", + "subType": "06" + } + } + }, + "azure_binData=00_det_auto_id": { + "kms": "azure", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAFvswfP3+jgia6rAyrypvbso3Xm4d7MEgJRUCWFYzA+9ov++vmeirgoTp/rFavTNOPb+61fvl1WKbVwrgODusaMg==", + "subType": "06" + } + } + }, + "azure_binData=00_det_explicit_id": { + "kms": "azure", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAFvswfP3+jgia6rAyrypvbso3Xm4d7MEgJRUCWFYzA+9ov++vmeirgoTp/rFavTNOPb+61fvl1WKbVwrgODusaMg==", + "subType": "06" + } + } + }, + "azure_binData=00_det_explicit_altname": { + "kms": "azure", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAFvswfP3+jgia6rAyrypvbso3Xm4d7MEgJRUCWFYzA+9ov++vmeirgoTp/rFavTNOPb+61fvl1WKbVwrgODusaMg==", + "subType": "06" + } + } + }, + "azure_binData=04_rand_auto_id": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFMzMC3BLn/zWE9dxpcD8G0h4aifSY0zSHS9xTVJXgq21s2WU++Ov2UvHatVozmtZltsUN9JvSWqOBQRkFsrXvI7bc4lYfOoOmfpTHFcRDA/c=", + "subType": "06" + } + } + }, + "azure_binData=04_rand_auto_altname": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFDlBN5hUTcjamOg/sgyeG0S52kphsjUgvlpuqHYz6VVdLtZ69cGHOVqqyml3x2rVqWUZJjd4ZodOhlwWq9p+i5IYNot2QaBvi8NZSaiThTc0=", + "subType": "06" + } + } + }, + "azure_binData=04_rand_explicit_id": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFjvS2ozJuAL3rCvyBpraVtgL91OMdiskmgYnyfKlzd8EhYLd1cL4yxnTUjRXx+W+p8uN0/QZo+mynhcWnwcq83raY+I1HftSTx+S6rZ0qyDM=", + "subType": "06" + } + } + }, + "azure_binData=04_rand_explicit_altname": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAFqUMd/I0yOdy5W4THvFc6yrgSzB6arkRs/06b0M9Ii+QtAY6vbz+/aJ0Iy3Jm8TahC1wOZVmTj5luQpr+PHZMCEAFadv+0K/Nsx6xVhAh9gg=", + "subType": "06" + } + } + }, + "azure_binData=04_det_auto_id": { + "kms": "azure", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAFmN+KMrERGmfmue8/hG4D+ZcGzxC2HntdYBLjEolzvS9FV5JH/adxyUAnMpyL8FNznARL51rbv/G1nXPn9mPabsQ4BtWEAQbHx9TiXd+xbB0=", + "subType": "06" + } + } + }, + "azure_binData=04_det_explicit_id": { + "kms": "azure", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAFmN+KMrERGmfmue8/hG4D+ZcGzxC2HntdYBLjEolzvS9FV5JH/adxyUAnMpyL8FNznARL51rbv/G1nXPn9mPabsQ4BtWEAQbHx9TiXd+xbB0=", + "subType": "06" + } + } + }, + "azure_binData=04_det_explicit_altname": { + "kms": "azure", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAFmN+KMrERGmfmue8/hG4D+ZcGzxC2HntdYBLjEolzvS9FV5JH/adxyUAnMpyL8FNznARL51rbv/G1nXPn9mPabsQ4BtWEAQbHx9TiXd+xbB0=", + "subType": "06" + } + } + }, + "azure_undefined_rand_explicit_id": { + "kms": "azure", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_undefined_rand_explicit_altname": { + "kms": "azure", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_undefined_det_explicit_id": { + "kms": "azure", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_undefined_det_explicit_altname": { + "kms": "azure", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_objectId_rand_auto_id": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAH3sYVJpCKi310YxndMwm5ltEbbiRO1RwZxxeEkzI8tptbNXC8t7RkrT8VSJZ43wbGYCiqH5RZy9v8pYwtUm4STw==", + "subType": "06" + } + } + }, + "azure_objectId_rand_auto_altname": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAHD7agzVEc0JwesHHhkpGYIDAHQ+3Hc691kqic6YmVvK2N45fD5aRKftaZNs5OxSj3tNHSo7lQ+DVtPj8uSSpsVg==", + "subType": "06" + } + } + }, + "azure_objectId_rand_explicit_id": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAHEgKgy2mpMLpfeEWqbvQOaRZAy+cEGXGon3e53/JoH6dZneEyyt4ZrcrK6uRqyUPWX0q104JbCYxfbtHtdzWgPQ==", + "subType": "06" + } + } + }, + "azure_objectId_rand_explicit_altname": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAHqSv6Nruw3TIi7y0FPRjSfnJmWSdv5XMhAtnHNkT8MVuHeM32ayo0yc8dTA1wlkRtAI5JrGxTfERCXYuCojvvXg==", + "subType": "06" + } + } + }, + "azure_objectId_det_auto_id": { + "kms": "azure", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAHcPRjIOyLDUJCDcdWkUySKCFS2AFkIa1OQyQAfC3Zh5HwJ1O7j2o+iYKRerhbni8lBiZH7EUMm1JcxM99lLC5jQ==", + "subType": "06" + } + } + }, + "azure_objectId_det_explicit_id": { + "kms": "azure", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAHcPRjIOyLDUJCDcdWkUySKCFS2AFkIa1OQyQAfC3Zh5HwJ1O7j2o+iYKRerhbni8lBiZH7EUMm1JcxM99lLC5jQ==", + "subType": "06" + } + } + }, + "azure_objectId_det_explicit_altname": { + "kms": "azure", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAHcPRjIOyLDUJCDcdWkUySKCFS2AFkIa1OQyQAfC3Zh5HwJ1O7j2o+iYKRerhbni8lBiZH7EUMm1JcxM99lLC5jQ==", + "subType": "06" + } + } + }, + "azure_bool_rand_auto_id": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAIYVWPvzSmiCs9LwRlv/AoQWhaS5mzoKX4W26M5eg/gPjOZbEVYOV80pWMxCcZWRAyV/NDWDUmKtRQDMU9b8lCJw==", + "subType": "06" + } + } + }, + "azure_bool_rand_auto_altname": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAIsAB01Ugqtw4T9SkuJBQN1y/ewpRAyz0vjFPdKI+jmPMmaXpMlXDJU8ZbTKm/nh6sjJCFcY5oZJ83ylbp2gHc6w==", + "subType": "06" + } + } + }, + "azure_bool_rand_explicit_id": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAIr8/qFd564X1mqHEhB0y7bzGFdrHuw+Gk45nXla3VvGHzeIJy6j2Wdl0uziWslMmBvNp8WweW+jQ6E2Fu7SiojQ==", + "subType": "06" + } + } + }, + "azure_bool_rand_explicit_altname": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAIWsca5FAnS2zhHnmKmexvvXMTgsZZ7uAFHnjQassUcay6mvIWH4hOnGiRxt5Zm0wO4S6cZq+PZrmEH5/n9rJcJQ==", + "subType": "06" + } + } + }, + "azure_bool_det_explicit_id": { + "kms": "azure", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "azure_bool_det_explicit_altname": { + "kms": "azure", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "azure_date_rand_auto_id": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAJwKo7XW5daIFlwY1mDAnJdHlcUgF+74oViL28hQGhde63pkPyyS6lPkYrc1gcCK5DL7PwsSX4Vb9SsNAG9860xw==", + "subType": "06" + } + } + }, + "azure_date_rand_auto_altname": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAJYZdWIqvqTztGKJkSASMEOjyrUFKnYql8fMIEzfEZWx2BYsIkxxOUUUCASg/Jsn09fTLVQ7yLD+LwycuI2uaXsw==", + "subType": "06" + } + } + }, + "azure_date_rand_explicit_id": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAJuWzKqi3KV8GbGGnT7i9N4BACUuNjt5AgKsjWIfrWRXK1+jRQFq0bYlVWaliT9CNIygL2aTF0H4eHl55PAI84MQ==", + "subType": "06" + } + } + }, + "azure_date_rand_explicit_altname": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAJ5JTtTuP4zTnEbaVlS/W59SrZ08LOC4ZIl+h+H4RnfHUfBXDwUou+APolVaYko+VZMKecrikdPeewgzWaqazJ1g==", + "subType": "06" + } + } + }, + "azure_date_det_auto_id": { + "kms": "azure", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAJCREIp/SPolAZcVU1iOmaJaN2tFId5HhrjNmhp6xhA1AIPLnN+U7TAqesxFN7iebR9fXI5fZxYNgyWqQC1rqUJw==", + "subType": "06" + } + } + }, + "azure_date_det_explicit_id": { + "kms": "azure", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAJCREIp/SPolAZcVU1iOmaJaN2tFId5HhrjNmhp6xhA1AIPLnN+U7TAqesxFN7iebR9fXI5fZxYNgyWqQC1rqUJw==", + "subType": "06" + } + } + }, + "azure_date_det_explicit_altname": { + "kms": "azure", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAJCREIp/SPolAZcVU1iOmaJaN2tFId5HhrjNmhp6xhA1AIPLnN+U7TAqesxFN7iebR9fXI5fZxYNgyWqQC1rqUJw==", + "subType": "06" + } + } + }, + "azure_null_rand_explicit_id": { + "kms": "azure", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "azure_null_rand_explicit_altname": { + "kms": "azure", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "azure_null_det_explicit_id": { + "kms": "azure", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "azure_null_det_explicit_altname": { + "kms": "azure", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "azure_regex_rand_auto_id": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAALsMm3W2ogEiI6m0l8dS5Xhqnw+vMBvN1EesOTqAZOk4tQleX6fWARwUUnjFxbuejU7ISb50fc/Ul+ntL9z/2nHQ==", + "subType": "06" + } + } + }, + "azure_regex_rand_auto_altname": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAALITQNQI0hfCeMTxH0Hce1Cf5tinQG+Bq8EolUACvxUUQcDqIXfFXn19tV/Qyj4lIdnnwh/18hiswgEpJRK7uLGw==", + "subType": "06" + } + } + }, + "azure_regex_rand_explicit_id": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAALw/1QI/bKeiGUrrtC+yXOTvxZ2mJjSelPPGOm1mge0ws8DsX0DPHmo6MjhnRO4u0c/LWiE3hwHG2rYjAFlFXZ5A==", + "subType": "06" + } + } + }, + "azure_regex_rand_explicit_altname": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAL6Sl58UfFCHCZzWIB4r19/ZjeSRAoWeTFCFedKiwyR8/xnL+8jzXK/9+vTIspP6j35lFapr+f4iBNB9WjdpYNKA==", + "subType": "06" + } + } + }, + "azure_regex_det_auto_id": { + "kms": "azure", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAALxshM91Tsql/8kPe3dC16oP36XSUIN6godiRVIJLJ+NAwYtEkThthQsln7CrkIxIx6npN6A/hw1CBJERS/cqWhw==", + "subType": "06" + } + } + }, + "azure_regex_det_explicit_id": { + "kms": "azure", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAALxshM91Tsql/8kPe3dC16oP36XSUIN6godiRVIJLJ+NAwYtEkThthQsln7CrkIxIx6npN6A/hw1CBJERS/cqWhw==", + "subType": "06" + } + } + }, + "azure_regex_det_explicit_altname": { + "kms": "azure", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAALxshM91Tsql/8kPe3dC16oP36XSUIN6godiRVIJLJ+NAwYtEkThthQsln7CrkIxIx6npN6A/hw1CBJERS/cqWhw==", + "subType": "06" + } + } + }, + "azure_dbPointer_rand_auto_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAMaAd1v/XCYM2Kzi/f4utR6aHOFORmzZ17EepEjkn5IeKshktUpPWjI/dBwSunn5Qxx2zI3nm06c3SDvp6tw8qb7u4qXjLQYhlsQ0bHvvm+vE=", + "subType": "06" + } + } + }, + "azure_dbPointer_rand_auto_altname": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAM6VNjkN9bMIzfC7AX0ZhOEXPpyPE0nzYq3c5TNHrgeGWdZDR9GVdbO9t55zQrQJJ2Mmevh8c0WaAUV+YODv7ty6TDBsPbaKWWqMzu/v9RXHo=", + "subType": "06" + } + } + }, + "azure_dbPointer_rand_explicit_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAM66tywuMhwdyUjxfl7EOdKHNCLeIPnct3PgKrAKlOQFjiNQUIA2ShVy0qYpJcvvFsuQ5e8Bjr0IqeBc8mC7n4euRSM1UXpLqI5XHgXMMaYpI=", + "subType": "06" + } + } + }, + "azure_dbPointer_rand_explicit_altname": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAMtPQEbZ4gWoSYjVZLd5X6j0XxutWY1Ecrys2ErKRgZaxP0uGe8uw0cnr2Z5PYylaYmsSicLwD1PwWY42PKmaGBDraHmdfqDOPvrNxhBrfU/E=", + "subType": "06" + } + } + }, + "azure_dbPointer_det_auto_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAMxUcVqq6RpAUCv08qGkmjuwVAIgLeYyh7xZnMeCYVGmhJKIP1Zdt1SvRGRV0jzwCQmXgxNd04adRwJnG/PRQIsL9aH3ilJgEnUbOo1nqR7yw=", + "subType": "06" + } + } + }, + "azure_dbPointer_det_explicit_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAMxUcVqq6RpAUCv08qGkmjuwVAIgLeYyh7xZnMeCYVGmhJKIP1Zdt1SvRGRV0jzwCQmXgxNd04adRwJnG/PRQIsL9aH3ilJgEnUbOo1nqR7yw=", + "subType": "06" + } + } + }, + "azure_dbPointer_det_explicit_altname": { + "kms": "azure", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAMxUcVqq6RpAUCv08qGkmjuwVAIgLeYyh7xZnMeCYVGmhJKIP1Zdt1SvRGRV0jzwCQmXgxNd04adRwJnG/PRQIsL9aH3ilJgEnUbOo1nqR7yw=", + "subType": "06" + } + } + }, + "azure_javascript_rand_auto_id": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAANWXPb5z3a0S7F26vkmBF3fV+oXYUj15OEtnSlXlUrc+gbhbPDxSvCPnTBEy5sNu4ndkvEZZxYgZInkF2q4rhlfQ==", + "subType": "06" + } + } + }, + "azure_javascript_rand_auto_altname": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAANN4mcwLz/J4eOUknhVsy6kdF1ThDP8cx6dNpOwJWAiyPHEsn+i6JmMTlfQMBrUp9HB/u3R+jLO5yz4XgLUKE8Tw==", + "subType": "06" + } + } + }, + "azure_javascript_rand_explicit_id": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAANJ+t5Z8hSQaoNzszzkWndAo4A0avDf9bKFa7euznz8ZYInnl9RUVqWMyxjSuIotAvTyYSJzxh+w2hKCgVf+MjEA==", + "subType": "06" + } + } + }, + "azure_javascript_rand_explicit_altname": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAANRLOQFpmkEg/KdWMmaurkNtUhy45rgtoipc9kQz6olgDWiMim81XC0AW5cOvjbHXL3w7Du28Kwdsp4j0PTTXHUQ==", + "subType": "06" + } + } + }, + "azure_javascript_det_auto_id": { + "kms": "azure", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAANUrNUS/7/dmKVWBd+2JKGEn1hxbFSyu3p5sDNatukG2m16t4WwxzmYAg8PuQbAxekprs7iaLA+7D2Kn3ZuMSQOw==", + "subType": "06" + } + } + }, + "azure_javascript_det_explicit_id": { + "kms": "azure", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAANUrNUS/7/dmKVWBd+2JKGEn1hxbFSyu3p5sDNatukG2m16t4WwxzmYAg8PuQbAxekprs7iaLA+7D2Kn3ZuMSQOw==", + "subType": "06" + } + } + }, + "azure_javascript_det_explicit_altname": { + "kms": "azure", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAANUrNUS/7/dmKVWBd+2JKGEn1hxbFSyu3p5sDNatukG2m16t4WwxzmYAg8PuQbAxekprs7iaLA+7D2Kn3ZuMSQOw==", + "subType": "06" + } + } + }, + "azure_symbol_rand_auto_id": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAORMcgtQSU+/2Qlq57neRrVuAFSeSwkqdo+z1fh6IKjyEzhCy+u5bTzSzTopyKJQTCUZA2mSpRezWkM87oiGfhMFkBRVreMcE62eH+BLlgUaM=", + "subType": "06" + } + } + }, + "azure_symbol_rand_auto_altname": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAOIKlAw/A3nwHn0tO2cYtJx0azB8MGmXtt+bRptzn8yHlUSpMpYaiU0ssBBiLkmMLAITYebLqDk3NHESyP7PvbSfX1E2XVn2Nf694ZqPWMec8=", + "subType": "06" + } + } + }, + "azure_symbol_rand_explicit_id": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAO8SXW76AEr/6D6zyP1RYwmwdVM2AINaXZn3Ipy+fynWTUV6XIPIRR7xMTttNo2zlh7fgXDZ28PmjooGlQzn0q0JVQmXPCIPM3aqAmMcgyuqg=", + "subType": "06" + } + } + }, + "azure_symbol_rand_explicit_altname": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAOtoJWm2Ucre0foHIiOutsX1WIyub7t3Lby3/F8zRXn+l6ixlTjAPgWFwpRnYg96Lt2ACDDQ9CO51ejr9qk0b8LDBwG3qU5Cuibsp7vo1VsdI=", + "subType": "06" + } + } + }, + "azure_symbol_det_auto_id": { + "kms": "azure", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAOvp/FMMmWVMkiuN51uFMFBiRQAcc9jftlNsHsLoNtohZaGni26kgX94b+/EI8pdWF5xA/73JlGlij0Rt+vC9s/zTDItRpn0bJL54WPphDcmA=", + "subType": "06" + } + } + }, + "azure_symbol_det_explicit_id": { + "kms": "azure", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAOvp/FMMmWVMkiuN51uFMFBiRQAcc9jftlNsHsLoNtohZaGni26kgX94b+/EI8pdWF5xA/73JlGlij0Rt+vC9s/zTDItRpn0bJL54WPphDcmA=", + "subType": "06" + } + } + }, + "azure_symbol_det_explicit_altname": { + "kms": "azure", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAOvp/FMMmWVMkiuN51uFMFBiRQAcc9jftlNsHsLoNtohZaGni26kgX94b+/EI8pdWF5xA/73JlGlij0Rt+vC9s/zTDItRpn0bJL54WPphDcmA=", + "subType": "06" + } + } + }, + "azure_javascriptWithScope_rand_auto_id": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAPCw9NnvJyuTYIgZxr1w1UiG85PGZ4rO62DWWDF98HwVM/Y6u7hNdNjkaWjYFsPMl38ioHw/pS8GFR62QmH2RAw/BV0wI7pNy2evANr3i3gKg=", + "subType": "06" + } + } + }, + "azure_javascriptWithScope_rand_auto_altname": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAPXQzqnQ2UWkIYof8/OfadNMa7iVKAbOaiu7YGm8iVrx+W6uxKLPFugVqHtQ29hYXXf33xr8rqGNxDlAe7/x1OeYEif71f7LUkmKF9WxJV9Ko=", + "subType": "06" + } + } + }, + "azure_javascriptWithScope_rand_explicit_id": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAP0nxlppgPyjLx0eBempbOlL21G6KbABSrE6+YuNDcsjJjxCQuLR9+aoAwa+yCDEC7GZ1E3oP489edKUuNpE4Ts26jy4aRegu4DmyECUeBwAg=", + "subType": "06" + } + } + }, + "azure_javascriptWithScope_rand_explicit_altname": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAPO89afu9Sb+cK9wwM1cO1DPjvu5UNyObjjTScy1hy9PzllJGfj7b84f0Ah74jPYsMPwI0Eslu/IYF3+5jmquq5Qp/VUQESlxqRqRK0xIeMfs=", + "subType": "06" + } + } + }, + "azure_javascriptWithScope_det_explicit_id": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_javascriptWithScope_det_explicit_altname": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_int_rand_auto_id": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAQUyy4uWmWdzypsK81q9egREg4s80X3L2hzxJzC+fL08Xzy1z9grpPPCfJrluUVKMMGmmZR8gJPJ70igN3unJbzg==", + "subType": "06" + } + } + }, + "azure_int_rand_auto_altname": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAQr4gyoHKpGsSJo8CMsYSJk/KilFMJhsDCmxrha7yfNW1uR5sjyZj4B4s6uTXGw76x7aR/AvecDlY3QFJb8L1mjg==", + "subType": "06" + } + } + }, + "azure_int_rand_explicit_id": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAQ0zgXYPV1MuEFksmDpVDoWkoZQelm3+rYrMiT64KYywO//75799W8TbR3a7O6Q/ErjKQOin2OCp8EWwZqTDdz5w==", + "subType": "06" + } + } + }, + "azure_int_rand_explicit_altname": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAQG+qz00yizREbP3tla1elMiwf8TKLbUU2XWUP+E0vey/wvbjTTIzqwUlz/b9St77CHJhavypP3hMrngXR9GapbQ==", + "subType": "06" + } + } + }, + "azure_int_det_auto_id": { + "kms": "azure", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAQCkJH+CataLqp/xBjO77QBprC2xPV+rE+goSZ3C6aqwXIeTYHTOqEbeaFb5iZcqYH5nWvNvnfbZSIMyvSfrPjhw==", + "subType": "06" + } + } + }, + "azure_int_det_explicit_id": { + "kms": "azure", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAQCkJH+CataLqp/xBjO77QBprC2xPV+rE+goSZ3C6aqwXIeTYHTOqEbeaFb5iZcqYH5nWvNvnfbZSIMyvSfrPjhw==", + "subType": "06" + } + } + }, + "azure_int_det_explicit_altname": { + "kms": "azure", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAQCkJH+CataLqp/xBjO77QBprC2xPV+rE+goSZ3C6aqwXIeTYHTOqEbeaFb5iZcqYH5nWvNvnfbZSIMyvSfrPjhw==", + "subType": "06" + } + } + }, + "azure_timestamp_rand_auto_id": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAARwcXYtx+A7g/zGkjGdkyVxZGCO9Nzj3D70NIpl2TeH2j9qYGP4DenwL1xSgrL2Ez+X58d2BvNhKrjA9y2w1Z8kA==", + "subType": "06" + } + } + }, + "azure_timestamp_rand_auto_altname": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAARQ0Pjx3l92Aqhn2e1hot2M9rQ6aLPE2Iw8AVhm5AD8FWywWih12Fn2p9+kiE33yKPOCyrTWQHKPtB4yYhqnJgGg==", + "subType": "06" + } + } + }, + "azure_timestamp_rand_explicit_id": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAARvFMlIzh2IjpHkTJ8buqTOqBA0+CxVDsZacUhSHVMgJLN+0DJsJy8OfkmKMu9Lk5hULY00Udoja87x+79mYfmeQ==", + "subType": "06" + } + } + }, + "azure_timestamp_rand_explicit_altname": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAAR+2SCd7V5ukAkh7CYpNPIatzTL8osNoA4Mb5jjjbos8eMamImw0fbH8YA+Rdm4CgGdQQ9VDX7MtMWlArkj0Jpew==", + "subType": "06" + } + } + }, + "azure_timestamp_det_auto_id": { + "kms": "azure", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAARe72T/oC09QGE1vuljb6ZEHa6llEwMLT+C4s9u1fREkOKndpmrOlGE8zOey4teizY1ypOMkIZ8GDQJJ4kLSpNkQ==", + "subType": "06" + } + } + }, + "azure_timestamp_det_explicit_id": { + "kms": "azure", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAARe72T/oC09QGE1vuljb6ZEHa6llEwMLT+C4s9u1fREkOKndpmrOlGE8zOey4teizY1ypOMkIZ8GDQJJ4kLSpNkQ==", + "subType": "06" + } + } + }, + "azure_timestamp_det_explicit_altname": { + "kms": "azure", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAARe72T/oC09QGE1vuljb6ZEHa6llEwMLT+C4s9u1fREkOKndpmrOlGE8zOey4teizY1ypOMkIZ8GDQJJ4kLSpNkQ==", + "subType": "06" + } + } + }, + "azure_long_rand_auto_id": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAASSSgX7k8iw0xFe0AiIzOu0e0P7Ujyfsk/Cdl0fR5X8V3QLVER+1Qa47Qpb8iWL2VLBSh+55HvIEtvhWn8SwXaog==", + "subType": "06" + } + } + }, + "azure_long_rand_auto_altname": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAASUhKr5K7ulGTeFbhIvJ2DDE10gRAFn5+2zqnsIFSY8lYV2PBYcENdeNBXZs6kyIAYhJdQyuOChVCerTI5jmQWDw==", + "subType": "06" + } + } + }, + "azure_long_rand_explicit_id": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAASHxawpjTHdXYRWQSZ7Qi7gFC+o4dW2mPH8s5nQkPFY/EubcJbdAZ5HFp66NfPaDJ/NSH6Vy+TkpX3683RC+bjSQ==", + "subType": "06" + } + } + }, + "azure_long_rand_explicit_altname": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAASVaMAv6UjuBOUZMJ9qz+58TQWmgaMpS9xrJziJY80ml9aRlDTtRubP7U40CgbDvrtY1QgHbkF/di1XDCB6iXMMg==", + "subType": "06" + } + } + }, + "azure_long_det_auto_id": { + "kms": "azure", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAS06L8oEPeMvVlA32VlobdOWG24OoyMbv9PyYsHLsbT0bHFwU7lYUSQG9EkYVRNPEDzvXpciE1jT7KT8CRY8XT/g==", + "subType": "06" + } + } + }, + "azure_long_det_explicit_id": { + "kms": "azure", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAS06L8oEPeMvVlA32VlobdOWG24OoyMbv9PyYsHLsbT0bHFwU7lYUSQG9EkYVRNPEDzvXpciE1jT7KT8CRY8XT/g==", + "subType": "06" + } + } + }, + "azure_long_det_explicit_altname": { + "kms": "azure", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQGVERAAAAAAAAAAAAAAAAAS06L8oEPeMvVlA32VlobdOWG24OoyMbv9PyYsHLsbT0bHFwU7lYUSQG9EkYVRNPEDzvXpciE1jT7KT8CRY8XT/g==", + "subType": "06" + } + } + }, + "azure_decimal_rand_auto_id": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAATJ6LZgPu9F+rPtYsMuvwOx62+g1dAk858BUtE9FjC/300DnbDiolhkHNcyoFs07NYUNgLthW2rISb/ejmsDCt/oqnf8zWYf9vrJEfHaS/Ocw=", + "subType": "06" + } + } + }, + "azure_decimal_rand_auto_altname": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAATX8eD6qFYWKwIGvXtQG79fXKuPW9hkIV0OwrmNNIqRltw6gPHl+/1X8Q6rgmjCxqvhB05AxTj7xz64gP+ILkPQY8e8VGuCOvOdwDo2IPwy18=", + "subType": "06" + } + } + }, + "azure_decimal_rand_explicit_id": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAATBjQ9E5wDdTS/iI1XDqGmDBC5aLbPB4nSyrjRLfv1zEoPRjmcHlQmMRJA0mori2VQv6EBFNHeczFCenJaSAkuh77czeXM2vH3T6qwEIDs4dw=", + "subType": "06" + } + } + }, + "azure_decimal_rand_explicit_altname": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AgGVERAAAAAAAAAAAAAAAAATtkjbhdve7MNuLaTm6qvaewuVUxeC1DMz1fd4RC4jeiBFMd5uZUVJTiOIerwQ6P5G5lkMlezKDWgKl2FUvZH6c7V3JknhsaWcV5iLWGUL6Zc=", + "subType": "06" + } + } + }, + "azure_decimal_det_explicit_id": { + "kms": "azure", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_decimal_det_explicit_altname": { + "kms": "azure", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_minKey_rand_explicit_id": { + "kms": "azure", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_minKey_rand_explicit_altname": { + "kms": "azure", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_minKey_det_explicit_id": { + "kms": "azure", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_minKey_det_explicit_altname": { + "kms": "azure", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_maxKey_rand_explicit_id": { + "kms": "azure", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "azure_maxKey_rand_explicit_altname": { + "kms": "azure", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "azure_maxKey_det_explicit_id": { + "kms": "azure", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "azure_maxKey_det_explicit_altname": { + "kms": "azure", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_double_rand_auto_id": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAABFoHQxnh1XSC0k1B01uFFg7rE9sZVBn4PXo26JX8gx9tuxu+4l9Avb23H9BfOzuWiEc43iw87K/W2y0VfKp5CCg==", + "subType": "06" + } + } + }, + "gcp_double_rand_auto_altname": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAABRkZkEtQEFB/r268cNfYRQbN4u5Cxjl9Uh+8wq9TFWLQH2E/9wj2vTLlxQ2cQsM7Qd+XxR5idjfBf9CKAfvUa/A==", + "subType": "06" + } + } + }, + "gcp_double_rand_explicit_id": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAABDSUZ+0BbDDEZxCXA+J2T6Js8Uor2dfXSf7s/hpLrg6dxcW2chpht9XLiLOXG5w83TzCAI5pF8cQgBpBpYjR8RQ==", + "subType": "06" + } + } + }, + "gcp_double_rand_explicit_altname": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAABCYxugs7L+4S+1rr0VILSbtBm79JPTLuzluQAv0+8hbu5Z6zReOL6Ta1vQH1oA+pSPGYA4euye3zNl1X6ZewbPw==", + "subType": "06" + } + } + }, + "gcp_double_det_explicit_id": { + "kms": "gcp", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "gcp_double_det_explicit_altname": { + "kms": "gcp", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "gcp_string_rand_auto_id": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAACx3wSslJEiD80YLTH0n4Bbs4yWVPQl15AU8pZMLLQePqEtI+BJy3t2bqNP1098jS0CGSf+LQmQvXhJn1aNFeMTw==", + "subType": "06" + } + } + }, + "gcp_string_rand_auto_altname": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAC5BTe5KP5UxSIk6dJlkz8aaZ/9fg44XPWHafiiL/48lcv3AWbu2gcBo1EDuc1sJQu6XMrtDCRQ7PCHsL7sEQMGQ==", + "subType": "06" + } + } + }, + "gcp_string_rand_explicit_id": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAACyJN55OcyXXJ71x8VphTaIuIg6kQtGgVKPhWx0LSdYc6JOjB6LTdA7SEWiSlSWWFZE26UmKcPbkbLDAYf4IVrzQ==", + "subType": "06" + } + } + }, + "gcp_string_rand_explicit_altname": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAACoa0d9gqfPP5s3+GoruwzxoQFgli8SmjpTVRLAOcFxqGdfrwSbpYffSw/OR45sZPxXCL6T2MtUvZsl7ukv0jBnw==", + "subType": "06" + } + } + }, + "gcp_string_det_auto_id": { + "kms": "gcp", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAACTCkyETcWayIZ9YEoQEBVIF3i7iXEe6M3KjYYaSVCYdqSbSHBzlwKWYbP+Xj/MMYBYTLZ1aiRQWCMK4gWPYppZw==", + "subType": "06" + } + } + }, + "gcp_string_det_explicit_id": { + "kms": "gcp", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAACTCkyETcWayIZ9YEoQEBVIF3i7iXEe6M3KjYYaSVCYdqSbSHBzlwKWYbP+Xj/MMYBYTLZ1aiRQWCMK4gWPYppZw==", + "subType": "06" + } + } + }, + "gcp_string_det_explicit_altname": { + "kms": "gcp", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAACTCkyETcWayIZ9YEoQEBVIF3i7iXEe6M3KjYYaSVCYdqSbSHBzlwKWYbP+Xj/MMYBYTLZ1aiRQWCMK4gWPYppZw==", + "subType": "06" + } + } + }, + "gcp_object_rand_auto_id": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAADy+8fkyeNYdIK001YogXfKc25zRXS1VGIFVWR6jRfrexy9C8LBBfX3iDwGNPbP2pkC3Tq16OoziQB6iNGf7s7yg==", + "subType": "06" + } + } + }, + "gcp_object_rand_auto_altname": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAADixoDdvm57gH8ooOaKI57WyZD5uaPmuYgmrgAFuV8I+oaalqYctnNSYlzQKCMQX/mIcTxvW3oOWY7+IzAz7npvw==", + "subType": "06" + } + } + }, + "gcp_object_rand_explicit_id": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAADvq0OAoijgHaVMhsoNMdfWFLyISDo6Y13sYM0CoBXS/oXJNIJJvhgKPbFSV/h4IgiDLy4qNYOTJQvpqt094RPgQ==", + "subType": "06" + } + } + }, + "gcp_object_rand_explicit_altname": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAADuTZF7/uqGjFbjzBYspPkxGWvvVAEN/ib8bfPOQrEobtTWuU+ju9H3TlT9DMuFy7RdUZnPB0D3HkM8+zky5xeBw==", + "subType": "06" + } + } + }, + "gcp_object_det_explicit_id": { + "kms": "gcp", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_object_det_explicit_altname": { + "kms": "gcp", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_array_rand_auto_id": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAE085kJIBX6S93D94bcRjkOegEKsksi2R1cxoVDoOpSdHh3S6bZAOh50W405wvnOKf3KTP9SICDUehQKQZSC026Y5dwVQ2GiM7PtpSedthKJs=", + "subType": "06" + } + } + }, + "gcp_array_rand_auto_altname": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAEk/FAXsaqyVr6I+MY5L0axeLhskcEfLZeB8whLMKbjLDLa8Iep+IdrFVSfKo03Zr/7Ah8Js01aT6+Vt4EDMJK0mGKZJOjsrAf3b6RS+Mzebg=", + "subType": "06" + } + } + }, + "gcp_array_rand_explicit_id": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAEDY7J9JGiurctYr7ytakNjcryVm42fkubcVpQpUYEkpK/G9NLGjrJuFgNW5ZVjYiPKEBbDB7vEtJqGux0BU++hrvVHNJ3wUT2mbDE18NE4KE=", + "subType": "06" + } + } + }, + "gcp_array_rand_explicit_altname": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAErFFlw8W9J2y+751RnYLw0TSK9ThD6sP3i4zPbZtiuhc90RFoJhScvqM9i4sDKuYePZZRLBxdX4EZhZClOmswCGDLCIWsQlSvCwgDcIsRR/w=", + "subType": "06" + } + } + }, + "gcp_array_det_explicit_id": { + "kms": "gcp", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_array_det_explicit_altname": { + "kms": "gcp", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_binData=00_rand_auto_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAF0R5BNkQKfm6wx/tob8nVGDEYV/pvy9UeCqc9gFNuB5d9KxCkgyxryV65rbB90OriqvWFO2jcxzchRYgRI3fQ+A==", + "subType": "06" + } + } + }, + "gcp_binData=00_rand_auto_altname": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAF4wcT8XGc3xNdKYDX5/cbUwPDdnkIXlWWCCYeSXSk2oWPxMZnPsVQ44nXKJJsKitoE3r/hL1sSG5239WzCWyx9g==", + "subType": "06" + } + } + }, + "gcp_binData=00_rand_explicit_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAF07OFs5mlx0AB6QBanaybLuhuFbG+19KxSqHlSgELcz6TQKI6equX97OZdaWSWf2SSeiYm5E6+Y3lgA5l4KxC2A==", + "subType": "06" + } + } + }, + "gcp_binData=00_rand_explicit_altname": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAFZ74Q7JMm7y2i3wRmjIRKefhmdnrhP1NXJgploi+44eQ2eRraZsW7peGPYyIfsXEbhgV5+aLmiYgvemBywfdogQ==", + "subType": "06" + } + } + }, + "gcp_binData=00_det_auto_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAFhwJkocj36WXoY3mg2GWUrJ5IQTo9MvkwEwRFKdkcxm9pX2PZPK7bN5ZWw3IFcQ/0GfaW6V4LYr8WarZdLF0p5g==", + "subType": "06" + } + } + }, + "gcp_binData=00_det_explicit_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAFhwJkocj36WXoY3mg2GWUrJ5IQTo9MvkwEwRFKdkcxm9pX2PZPK7bN5ZWw3IFcQ/0GfaW6V4LYr8WarZdLF0p5g==", + "subType": "06" + } + } + }, + "gcp_binData=00_det_explicit_altname": { + "kms": "gcp", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAFhwJkocj36WXoY3mg2GWUrJ5IQTo9MvkwEwRFKdkcxm9pX2PZPK7bN5ZWw3IFcQ/0GfaW6V4LYr8WarZdLF0p5g==", + "subType": "06" + } + } + }, + "gcp_binData=04_rand_auto_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAFmDO47RTVXzm8D4hfhLICILrQJg3yOwG3HYfCdz7yaanPow2Y6bMxvXxk+kDS29aS8pJKDqJQQoMGc1ZFD3yYKsLQHRi/8rW6TNDQd4sCQ00=", + "subType": "06" + } + } + }, + "gcp_binData=04_rand_auto_altname": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAFpiu9Q3LTuPmgdWBqo5Kw0vGF9xU1rMyE4xwR8GccZ7ZMrUcR4AnZnAP7ah5Oz8e7qonNYX4d09obesYSLlIjyK7J7qg+GWiEURgbvmOngaA=", + "subType": "06" + } + } + }, + "gcp_binData=04_rand_explicit_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAFHRy8dveGuMng9WMmadIp39jD7iEfl3bEjKmzyNoAc0wIcSJZo9kdGbNEwZ4p+A1gz273fmAt/AJwAxwvqdlanLWBr4wiSKz1Mu9VaBcTlyY=", + "subType": "06" + } + } + }, + "gcp_binData=04_rand_explicit_altname": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAFiqO+sKodqXuVox0zTbKuY4Ng0QE1If2hDLWXljAEZdYABPk20UJyL/CHR49WP2Cwvi4evJCf8sEfKpR+ugPiyxWzP3iVe6qqTzP93BBjqoc=", + "subType": "06" + } + } + }, + "gcp_binData=04_det_auto_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAFEp5Gut6iENHUqDMVdBm4cxQy35gnslTf7vSWW9InFh323BvaTTiubxbxTiMKIa/u47MfMprL9HNQSwgpAQc4lped+YnlRW8RYvTcG4frFtA=", + "subType": "06" + } + } + }, + "gcp_binData=04_det_explicit_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAFEp5Gut6iENHUqDMVdBm4cxQy35gnslTf7vSWW9InFh323BvaTTiubxbxTiMKIa/u47MfMprL9HNQSwgpAQc4lped+YnlRW8RYvTcG4frFtA=", + "subType": "06" + } + } + }, + "gcp_binData=04_det_explicit_altname": { + "kms": "gcp", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAFEp5Gut6iENHUqDMVdBm4cxQy35gnslTf7vSWW9InFh323BvaTTiubxbxTiMKIa/u47MfMprL9HNQSwgpAQc4lped+YnlRW8RYvTcG4frFtA=", + "subType": "06" + } + } + }, + "gcp_undefined_rand_explicit_id": { + "kms": "gcp", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_undefined_rand_explicit_altname": { + "kms": "gcp", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_undefined_det_explicit_id": { + "kms": "gcp", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_undefined_det_explicit_altname": { + "kms": "gcp", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_objectId_rand_auto_id": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAH8Kt6coc8bPI4QIwS1tIdk6pPA05xlZvrOyAQgvoqaozMtWzG15OunQLDdS3yJ5WRiV7kO6CIKqRrvL2RykB5sw==", + "subType": "06" + } + } + }, + "gcp_objectId_rand_auto_altname": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAHU5Yzmz2mbgNQrGSvglgVuv14nQWzipBkZUVSO4eYZ7wLrj/9t0fnizsu7Isgg5oA9fV0Snh/A9pDnHZWoccXUw==", + "subType": "06" + } + } + }, + "gcp_objectId_rand_explicit_id": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAHsdq5/FLqbjMDiNzf+6k9yxUtFVjS/xSqErqaboOl21934pAzgkOzBGodpKKFuK0Ta4f3h21XS+84wlIYPMlTtw==", + "subType": "06" + } + } + }, + "gcp_objectId_rand_explicit_altname": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAHokIdXxNQ/NBMdMAVNxyVuz/J5pMMdtfxxJxr7PbsRJ3FoD2QNjTgE1Wsz0G4o09Wv9UWD+/mIqPVlLgx1sRtPw==", + "subType": "06" + } + } + }, + "gcp_objectId_det_auto_id": { + "kms": "gcp", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAHkcbaj3Hy3b4HkjRkMgiw5h6jBW7Sc56QSJmAPmVSc2T4B8d79A49dW0RyEiInZJcnVRjrYzUTRtgRaG4/FRd8g==", + "subType": "06" + } + } + }, + "gcp_objectId_det_explicit_id": { + "kms": "gcp", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAHkcbaj3Hy3b4HkjRkMgiw5h6jBW7Sc56QSJmAPmVSc2T4B8d79A49dW0RyEiInZJcnVRjrYzUTRtgRaG4/FRd8g==", + "subType": "06" + } + } + }, + "gcp_objectId_det_explicit_altname": { + "kms": "gcp", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAHkcbaj3Hy3b4HkjRkMgiw5h6jBW7Sc56QSJmAPmVSc2T4B8d79A49dW0RyEiInZJcnVRjrYzUTRtgRaG4/FRd8g==", + "subType": "06" + } + } + }, + "gcp_bool_rand_auto_id": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAIf7vUYS5XFrEU4g03lzj9dk8a2MkaQdlH8nE/507D2Gm5XKQLi2jCENZ9UaQm3MQtVr4Uqrgz2GZiQHt9mXcG3w==", + "subType": "06" + } + } + }, + "gcp_bool_rand_auto_altname": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAIdOC4Tx/TaVLRtOL/Qh8RUFIzHFB6nSegZoITwZeDethd8V3+R+aIAgzfN3pvmZzagHyVCm2nbNYJNdjOJhuDrg==", + "subType": "06" + } + } + }, + "gcp_bool_rand_explicit_id": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAIzB14mX2vaZdiW9kGc+wYEgTCXA0FB5AVEyuERD00+K7U5Otlc6ZUwMtb9nGUu+M7PnnfxiDFHCrUWrTkAZzSUw==", + "subType": "06" + } + } + }, + "gcp_bool_rand_explicit_altname": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAIhRLg79ACCMfeERBgG1wirirrZXZzbK11RxHkAbf14Fji2L3sdMBdLBU5I028+rmtDdC7khcNMt11V6XGKpAjnA==", + "subType": "06" + } + } + }, + "gcp_bool_det_explicit_id": { + "kms": "gcp", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "gcp_bool_det_explicit_altname": { + "kms": "gcp", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "gcp_date_rand_auto_id": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAJL+mjI8xBmSahOOi3XkGRGxjhGNdJb445KZtRAaUdCV0vMKbrefuiDHJDPCYo7mLYNhRSIhQfs63IFYMrlKP26A==", + "subType": "06" + } + } + }, + "gcp_date_rand_auto_altname": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAJbeyqO5FRmqvPYyOb0tdKtK6JOg8QKbCl37/iFeEm7N0T0Pjb8Io4U0ndB3O6fjokc3kDQrZcQkV+OFWIMuKFjw==", + "subType": "06" + } + } + }, + "gcp_date_rand_explicit_id": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAJVz3rSYIcoYtM0tZ8pB2Ytgh8RvYPeZvW7aUVJfZkZlIhfUHOHEf5kHqxzt8E1l2n3lmK/7ZVCFUuCCmr8cZyWw==", + "subType": "06" + } + } + }, + "gcp_date_rand_explicit_altname": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAJAiQqNyUcpuDEpFt7skp2NSHFCux2XObrIIFgXReYgtWoapL/n4zksJXl89PGavzNPBZbzgEa8uwwAe+S+Y6TLg==", + "subType": "06" + } + } + }, + "gcp_date_det_auto_id": { + "kms": "gcp", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAJmATV2A1P5DmrS8uES6AMD9y+EU3x7u4K4J0p296iSkCEgIdZZORhPIEnuJK3FHw1II6IEShW2nd7sOJRZSGKcg==", + "subType": "06" + } + } + }, + "gcp_date_det_explicit_id": { + "kms": "gcp", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAJmATV2A1P5DmrS8uES6AMD9y+EU3x7u4K4J0p296iSkCEgIdZZORhPIEnuJK3FHw1II6IEShW2nd7sOJRZSGKcg==", + "subType": "06" + } + } + }, + "gcp_date_det_explicit_altname": { + "kms": "gcp", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAJmATV2A1P5DmrS8uES6AMD9y+EU3x7u4K4J0p296iSkCEgIdZZORhPIEnuJK3FHw1II6IEShW2nd7sOJRZSGKcg==", + "subType": "06" + } + } + }, + "gcp_null_rand_explicit_id": { + "kms": "gcp", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "gcp_null_rand_explicit_altname": { + "kms": "gcp", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "gcp_null_det_explicit_id": { + "kms": "gcp", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "gcp_null_det_explicit_altname": { + "kms": "gcp", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "gcp_regex_rand_auto_id": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAALiebb3hWwJRqlgVEhLYKKvo6cnlU7BFnZnvlZ8GuIr11fUvcnS9Tg2m7vPmfL7WVyuNrXlR48x28Es49YuaxuIg==", + "subType": "06" + } + } + }, + "gcp_regex_rand_auto_altname": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAALouDFNLVgBXqhJvBRj9DKacuD1AQ2NAVDW93P9NpZDFFwGOFxmKUcklbPj8KkHqvma8ovVUBTLLUDR+tKFRvC2Q==", + "subType": "06" + } + } + }, + "gcp_regex_rand_explicit_id": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAALtdcT9+3R1he4eniT+1opqs/YtujFlqzBXssv+hCKhJQVY/IXde32nNpQ1WTgUc7jfIJl/v9HvuA9cDHPtDWWTg==", + "subType": "06" + } + } + }, + "gcp_regex_rand_explicit_altname": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAALAwlRAlj4Zpn+wu9eOcs5CsNgrkVwrgmu1tc4wyQp0Lt+3UcplYsXQMrMPcTx3yB0JcI4Kh65n/DrAaA+G/a6iw==", + "subType": "06" + } + } + }, + "gcp_regex_det_auto_id": { + "kms": "gcp", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAALbCutQ7D94gk0djewcQiEdMFVVa21+Dn5enQf/mqPi3o7vPy7OejDBk9fiZRffsioRMhlx2cxqa8T3+AkeN96yg==", + "subType": "06" + } + } + }, + "gcp_regex_det_explicit_id": { + "kms": "gcp", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAALbCutQ7D94gk0djewcQiEdMFVVa21+Dn5enQf/mqPi3o7vPy7OejDBk9fiZRffsioRMhlx2cxqa8T3+AkeN96yg==", + "subType": "06" + } + } + }, + "gcp_regex_det_explicit_altname": { + "kms": "gcp", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAALbCutQ7D94gk0djewcQiEdMFVVa21+Dn5enQf/mqPi3o7vPy7OejDBk9fiZRffsioRMhlx2cxqa8T3+AkeN96yg==", + "subType": "06" + } + } + }, + "gcp_dbPointer_rand_auto_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAMG8P+Y2YNIgknxE0/yPDCHASBvCU1IJwsEyaJPuOjn03enxEN7z/wbjVMN0lGUptDP3SVL+OIZtQ35VRP84MtnbdhcfZWqMhLjzrCjmtHUEg=", + "subType": "06" + } + } + }, + "gcp_dbPointer_rand_auto_altname": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAMKCLFUN6ApB5fSVEWazRddhKTEwgqI/mxfe0BBxht69pZQYhTjhOJP0YcIrtr+RCeHOa4FIJgQod1CFOellIzO5YH5CuV4wPxCAlOdbJcBK8=", + "subType": "06" + } + } + }, + "gcp_dbPointer_rand_explicit_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAM7ULEA6uKKv4Pu4Sa3aAt7dXtEwfQC98aJoLBapHT+xXtn5GWPynOZQNtV3lGaYExQjiGdYbzOcav3SVy/sYTe3ktgkQnuZfe0tk0zyvKIMM=", + "subType": "06" + } + } + }, + "gcp_dbPointer_rand_explicit_altname": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAMoMveHO1MadAKuT498xiKWWBUKRbH7k7P2YETDg/BufVw0swos07rk6WJa1vqyF61QEmACjy4pmlK/5P0VfKJBAIvif51YqHPQkobJVS3nVA=", + "subType": "06" + } + } + }, + "gcp_dbPointer_det_auto_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAMz+9m1bE+Th9YeyPmJdtJPO0F5QYsGYtU/Eom/LSoYjDmTmV2ehkKx/cevIxJfZUc+Mvv/uGoeuubGl8tiX4l+f6yLrSIS6QBtIHYKXk+JNE=", + "subType": "06" + } + } + }, + "gcp_dbPointer_det_explicit_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAMz+9m1bE+Th9YeyPmJdtJPO0F5QYsGYtU/Eom/LSoYjDmTmV2ehkKx/cevIxJfZUc+Mvv/uGoeuubGl8tiX4l+f6yLrSIS6QBtIHYKXk+JNE=", + "subType": "06" + } + } + }, + "gcp_dbPointer_det_explicit_altname": { + "kms": "gcp", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAMz+9m1bE+Th9YeyPmJdtJPO0F5QYsGYtU/Eom/LSoYjDmTmV2ehkKx/cevIxJfZUc+Mvv/uGoeuubGl8tiX4l+f6yLrSIS6QBtIHYKXk+JNE=", + "subType": "06" + } + } + }, + "gcp_javascript_rand_auto_id": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAANqBD0ITMn4BaFnDp7BX7vXbRBkFwmjQRVUeBbwsQtv5WVlJMAd/2+w7tyH8Wc44x0/9U/DA5GVhpTrtdDyPBI3w==", + "subType": "06" + } + } + }, + "gcp_javascript_rand_auto_altname": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAANtA0q4mbkAaKX4x1xk0/094Mln0wnh2bYnI6s6dh+l2WLDH7A9JMZxCl6kc4uOsEfbOvjP/PLIYtdMGs14EjM5A==", + "subType": "06" + } + } + }, + "gcp_javascript_rand_explicit_id": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAANfrW3pmeiFdBFt5tJS6Auq9Wo/J4r/vMRiueLWxig5S1zYuf9kFPJMK/nN9HqQPIcBIJIC2i/uEPgeepaNXACCw==", + "subType": "06" + } + } + }, + "gcp_javascript_rand_explicit_altname": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAANL7UZNzpwfwhRn/HflWIE9CSxGYNwLSo9d86HsOJ42rrZKq6HQqm/hiEAg0lyqCxVIVFxYEc2BUWSaq4/+SSyZw==", + "subType": "06" + } + } + }, + "gcp_javascript_det_auto_id": { + "kms": "gcp", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAANB2d97R8nUJqnG0JPsWzyFe5pct5jvUljdkPnlZvLN1ZH+wSu4WmLfjri6IzzYP//f8tywn4Il+R4lZ0Kr/RAeA==", + "subType": "06" + } + } + }, + "gcp_javascript_det_explicit_id": { + "kms": "gcp", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAANB2d97R8nUJqnG0JPsWzyFe5pct5jvUljdkPnlZvLN1ZH+wSu4WmLfjri6IzzYP//f8tywn4Il+R4lZ0Kr/RAeA==", + "subType": "06" + } + } + }, + "gcp_javascript_det_explicit_altname": { + "kms": "gcp", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAANB2d97R8nUJqnG0JPsWzyFe5pct5jvUljdkPnlZvLN1ZH+wSu4WmLfjri6IzzYP//f8tywn4Il+R4lZ0Kr/RAeA==", + "subType": "06" + } + } + }, + "gcp_symbol_rand_auto_id": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAOsGdnr6EKcBdOAvYrP0o1pWbhhJbYsqfVwwwS1zq6ZkBayOss2J3TuYwBGXhJFlq3iIiWLdxGQ883XIvuAECnqUNuvpK2rOLwtDg8xJLiH24=", + "subType": "06" + } + } + }, + "gcp_symbol_rand_auto_altname": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAOpfa6CUSnJBvnWdd7pSZ2pXAbYm68Yka6xa/fuyhVx/Tc926/JpqmOmQtXqbOj8dZra0rQ3/yxHySwgD7s9Qr+xvyL7LvAguGkGmEV5H4Xz4=", + "subType": "06" + } + } + }, + "gcp_symbol_rand_explicit_id": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAO085iqYGFdtjiFWHcNqE0HuKMNHmk49DVh+pX8Pb4p3ehB57JL1nRqaXqHPqhFenxSEInT/te9HQRr+ADcHADvUGsScfm/n85v85nq6X+5y4=", + "subType": "06" + } + } + }, + "gcp_symbol_rand_explicit_altname": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAOiidb+2TsbAb2wc7MtDzb/UYsjgVNSw410Sz9pm+Uy7aZROE5SURKXdLjrCH2ZM2a+XCAl3o9yAoNgmAjEvYVxjmyzLK00EVjT42MBOrdA+k=", + "subType": "06" + } + } + }, + "gcp_symbol_det_auto_id": { + "kms": "gcp", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAOFBGo77joqvZl7QQMB9ebMsAI3uro8ILQTJsTUgAqNzSh1mNzqihGHZYe84xtgMrVxNuwcjkidkRbNnLXWLuarOx4tgmOLx5A5G1eYEe3s7Q=", + "subType": "06" + } + } + }, + "gcp_symbol_det_explicit_id": { + "kms": "gcp", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAOFBGo77joqvZl7QQMB9ebMsAI3uro8ILQTJsTUgAqNzSh1mNzqihGHZYe84xtgMrVxNuwcjkidkRbNnLXWLuarOx4tgmOLx5A5G1eYEe3s7Q=", + "subType": "06" + } + } + }, + "gcp_symbol_det_explicit_altname": { + "kms": "gcp", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAOFBGo77joqvZl7QQMB9ebMsAI3uro8ILQTJsTUgAqNzSh1mNzqihGHZYe84xtgMrVxNuwcjkidkRbNnLXWLuarOx4tgmOLx5A5G1eYEe3s7Q=", + "subType": "06" + } + } + }, + "gcp_javascriptWithScope_rand_auto_id": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAPUsQHeXWhdmyfQ2Sq1ev1HMuMhBTc/FZFKO9tMMcI9qzjr+z4IdCOFCcx24/T/6NCsDpMiOGNnCdaBCCNRwNM0CTIkpHNLO+RSZORDgAsm9Q=", + "subType": "06" + } + } + }, + "gcp_javascriptWithScope_rand_auto_altname": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAPRZawtuu0gErebyFqiQw0LxniWhdeujGzaqfAXriGo/2fU7PalzTlWQa8wsv0y7Q/i1K4JbQwCEFpJWLppmtZshCGbVWjpPljB2BH4NNrLPE=", + "subType": "06" + } + } + }, + "gcp_javascriptWithScope_rand_explicit_id": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAP0qkQjuKmKIqdrsrR9djxt+1jFlEL7K9bP1oz7QWuY38dZJOoGwa6G1bP4wDzjsucJLCEgU2IY+t7BHraBFXvR/Aar8ID5eXcvJ7iOPIyqUw=", + "subType": "06" + } + } + }, + "gcp_javascriptWithScope_rand_explicit_altname": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAP6L41iuBWGLg3hQZuhXp4MupTQvIT07+/+CRY292sC02mehk5BkuSOEVrehlvyvBJFKia4Bqd/UWvY8PnUPLqFKTLnokONWbAuh36y3gjStw=", + "subType": "06" + } + } + }, + "gcp_javascriptWithScope_det_explicit_id": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_javascriptWithScope_det_explicit_altname": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_int_rand_auto_id": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAQ+6oRKWMSvC+3UGrHSyGeVlR9bFnZtFTmYlUoGn04k6ndtCl8rsmBVUV6dMMYd7znnZtTSIGPI8q6jwf/NJjdIw==", + "subType": "06" + } + } + }, + "gcp_int_rand_auto_altname": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAQnz5jAbrrdutTPFA4m3MvlVJr3bpurTKY5xjwO5k8DZpeWTJzr+kVEJjG6M8/RgC/0UFNgBBrDbDhYa8PZHRijw==", + "subType": "06" + } + } + }, + "gcp_int_rand_explicit_id": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAQfRFoxUgjrv8up/eZ/fLlr/z++d/jFm30nYvKqsnQT7vkmmujJWc8yAtthR9OI6W5biBgAkounqRHhvatLZC6gA==", + "subType": "06" + } + } + }, + "gcp_int_rand_explicit_altname": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAQY/ePk59RY6vLejx9a5ITwkT9000KAubVSqMoQwv7lNXO+GKZfZoLHG6k1MA/IxTvl1Zbz1Tw1bTctmj0HPEGNA==", + "subType": "06" + } + } + }, + "gcp_int_det_auto_id": { + "kms": "gcp", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAQE9RVV9pOuysUUEGKq0u6ztFM0gTpoOHcHsTFQstA7+L9XTvxWEgL3RgNeq5KtKdODlxl62niV8dnQwlSoDSSWw==", + "subType": "06" + } + } + }, + "gcp_int_det_explicit_id": { + "kms": "gcp", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAQE9RVV9pOuysUUEGKq0u6ztFM0gTpoOHcHsTFQstA7+L9XTvxWEgL3RgNeq5KtKdODlxl62niV8dnQwlSoDSSWw==", + "subType": "06" + } + } + }, + "gcp_int_det_explicit_altname": { + "kms": "gcp", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAQE9RVV9pOuysUUEGKq0u6ztFM0gTpoOHcHsTFQstA7+L9XTvxWEgL3RgNeq5KtKdODlxl62niV8dnQwlSoDSSWw==", + "subType": "06" + } + } + }, + "gcp_timestamp_rand_auto_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAARLnk1LpJIriKr6iiY1yBDGnfkRaHNwWcQyL+mORtYC4+AQ6oMv0qpGrJxS2QCbYY1tGmAISqZHCIExCG+TIv4bw==", + "subType": "06" + } + } + }, + "gcp_timestamp_rand_auto_altname": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAARaqYXh9AVZI6gvRZrBwbprE5P3K5Qf4PIK1ca+mLRNOof0EExyAhtku7mYXusLeq0ww/tV6Zt1cA36KsT8a0Nog==", + "subType": "06" + } + } + }, + "gcp_timestamp_rand_explicit_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAARLXzBjkCN8BpfXDIrb94kuZCD07Uo/DMBfMIWQtAb1++tTheUoY2ClQz33Luh4g8NXwuMJ7h8ufE70N2+b1yrUg==", + "subType": "06" + } + } + }, + "gcp_timestamp_rand_explicit_altname": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAARe44QH9ZvTAuHsWhEMoue8eHod+cJpBm+Kl/Xtw7NI/6UTOOHC5Kkg20EvX3+GwXdAGk0bUSCFiTZb/yPox1OlA==", + "subType": "06" + } + } + }, + "gcp_timestamp_det_auto_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAARzXjP6d6j/iQxiz1/TC/m+IfAGLFH9wY2ksS//i9x15QttlhcRrT3XmPvxaP5OjTHac4Gq3m2aXiJH56lETyl8A==", + "subType": "06" + } + } + }, + "gcp_timestamp_det_explicit_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAARzXjP6d6j/iQxiz1/TC/m+IfAGLFH9wY2ksS//i9x15QttlhcRrT3XmPvxaP5OjTHac4Gq3m2aXiJH56lETyl8A==", + "subType": "06" + } + } + }, + "gcp_timestamp_det_explicit_altname": { + "kms": "gcp", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAARzXjP6d6j/iQxiz1/TC/m+IfAGLFH9wY2ksS//i9x15QttlhcRrT3XmPvxaP5OjTHac4Gq3m2aXiJH56lETyl8A==", + "subType": "06" + } + } + }, + "gcp_long_rand_auto_id": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAASuGZs48eEyVBJ9vvM6cvRySfuR0WM4kL7lx52rSGXBKtkZywyP5rJwNtRn9WTBMDqc1O/4jUgYXpqHx39SLhUPA==", + "subType": "06" + } + } + }, + "gcp_long_rand_auto_altname": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAS/62F71oKTX1GlvOP89uNhXpIyLZ5OdnuLeM/hvL5HWyOudSb06cG3+xnPg3QgppAYFK5X2PGgrEcrA87AykLPg==", + "subType": "06" + } + } + }, + "gcp_long_rand_explicit_id": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAASSgx+p4YzTvjZ+GCZCFHEKHNXJUSloPnLRHE4iJ515Epb8Tox7h8/aIAkB3ulnDS9BiT5UKdye2TWf8OBEwkXzg==", + "subType": "06" + } + } + }, + "gcp_long_rand_explicit_altname": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAAStqszyEfltpgd3aYeoyqaJX27OX861o06VhNX/N2fdSfKx0NQq/hWlWTkX6hK3hjCijiTtHmhFQR6QLkHD/6THw==", + "subType": "06" + } + } + }, + "gcp_long_det_auto_id": { + "kms": "gcp", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAS0wJHtZKnxJlWnlSu0xuq7bZR25UdwcbdCRSaXBC0EXEFuqlzrZSn1lcwKPKGZQO8EQ6SdQDqK95alMLmM8eQrQ==", + "subType": "06" + } + } + }, + "gcp_long_det_explicit_id": { + "kms": "gcp", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAS0wJHtZKnxJlWnlSu0xuq7bZR25UdwcbdCRSaXBC0EXEFuqlzrZSn1lcwKPKGZQO8EQ6SdQDqK95alMLmM8eQrQ==", + "subType": "06" + } + } + }, + "gcp_long_det_explicit_altname": { + "kms": "gcp", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ARgjwAAAAAAAAAAAAAAAAAAS0wJHtZKnxJlWnlSu0xuq7bZR25UdwcbdCRSaXBC0EXEFuqlzrZSn1lcwKPKGZQO8EQ6SdQDqK95alMLmM8eQrQ==", + "subType": "06" + } + } + }, + "gcp_decimal_rand_auto_id": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAATg4U3nbHBX/Az3ie2yurEIJO6cFryQWKiCpBbx1z0NF7RXd7kFC1XzaY6zcBjfl2AfRO8FFmgjTmFXb6gTRSSF0iAZJZTslfe3n6YFtwSKDI=", + "subType": "06" + } + } + }, + "gcp_decimal_rand_auto_altname": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAATdSSyp0ewboV5zI3T3TV/FOrdx0UQbFHhqcH+yqpotoWPSw5dxE+BEoihYLeaPKuVU/rUIY4TUv05Egj7Ovg62Kpk3cPscxsGtE/T2Ppbt6o=", + "subType": "06" + } + } + }, + "gcp_decimal_rand_explicit_id": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAATl7k20T22pf5Y9knVwIDyOIlbHyZBJqyi3Mai8APEZIYjpSKDKs8QNAH69CIjupyge8Izw4Cuch0bRrvMbp6YFfrUgk1JIQ4iLKkqqzHpBTY=", + "subType": "06" + } + } + }, + "gcp_decimal_rand_explicit_altname": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AhgjwAAAAAAAAAAAAAAAAAATF7YLkhkuLhXdxrQk2fJTs128tRNYHeodkqw7ha/TxW3Czr5gE272gnkdzfNoS7uu9XwOr1yjrC6y/8gHALAWn77WvGrAlBktLQbIIinsuds=", + "subType": "06" + } + } + }, + "gcp_decimal_det_explicit_id": { + "kms": "gcp", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_decimal_det_explicit_altname": { + "kms": "gcp", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_minKey_rand_explicit_id": { + "kms": "gcp", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_minKey_rand_explicit_altname": { + "kms": "gcp", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_minKey_det_explicit_id": { + "kms": "gcp", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_minKey_det_explicit_altname": { + "kms": "gcp", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_maxKey_rand_explicit_id": { + "kms": "gcp", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_maxKey_rand_explicit_altname": { + "kms": "gcp", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_maxKey_det_explicit_id": { + "kms": "gcp", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_maxKey_det_explicit_altname": { + "kms": "gcp", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } } -} +} \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-key-aws.json b/tests/SpecTests/client-side-encryption/corpus/corpus-key-aws.json index 06f2f06dc..eca6cf912 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus-key-aws.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-key-aws.json @@ -1,29 +1,29 @@ { "status": { "$numberInt": "1" - }, + }, "_id": { "$binary": { - "base64": "AWSAAAAAAAAAAAAAAAAAAA==", + "base64": "AWSAAAAAAAAAAAAAAAAAAA==", "subType": "04" } - }, + }, "masterKey": { - "region": "us-east-1", - "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", "provider": "aws" - }, + }, "updateDate": { "$date": { "$numberLong": "1557827033449" } - }, + }, "keyMaterial": { "$binary": { - "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", "subType": "00" } - }, + }, "creationDate": { "$date": { "$numberLong": "1557827033449" diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-key-azure.json b/tests/SpecTests/client-side-encryption/corpus/corpus-key-azure.json new file mode 100644 index 000000000..31a564edb --- /dev/null +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-key-azure.json @@ -0,0 +1,33 @@ +{ + "_id": { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "n+HWZ0ZSVOYA3cvQgP7inN4JSXfOH85IngmeQxRpQHjCCcqT3IFqEWNlrsVHiz3AELimHhX4HKqOLWMUeSIT6emUDDoQX9BAv8DR1+E1w4nGs/NyEneac78EYFkK3JysrFDOgl2ypCCTKAypkn9CkAx1if4cfgQE93LW4kczcyHdGiH36CIxrCDGv1UzAvERN5Qa47DVwsM6a+hWsF2AAAJVnF0wYLLJU07TuRHdMrrphPWXZsFgyV+lRqJ7DDpReKNO8nMPLV/mHqHBHGPGQiRdb9NoJo8CvokGz4+KE8oLwzKf6V24dtwZmRkrsDV4iOhvROAzz+Euo1ypSkL3mw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1601573901680" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1601573901680" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + }, + "keyAltNames": ["azure"] +} \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-key-gcp.json b/tests/SpecTests/client-side-encryption/corpus/corpus-key-gcp.json new file mode 100644 index 000000000..79d6999b0 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-key-gcp.json @@ -0,0 +1,35 @@ +{ + "_id": { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "CiQAIgLj0WyktnB4dfYHo5SLZ41K4ASQrjJUaSzl5vvVH0G12G0SiQEAjlV8XPlbnHDEDFbdTO4QIe8ER2/172U1ouLazG0ysDtFFIlSvWX5ZnZUrRMmp/R2aJkzLXEt/zf8Mn4Lfm+itnjgo5R9K4pmPNvvPKNZX5C16lrPT+aA+rd+zXFSmlMg3i5jnxvTdLHhg3G7Q/Uv1ZIJskKt95bzLoe0tUVzRWMYXLIEcohnQg==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1601574333107" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1601574333107" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + }, + "keyAltNames": ["gcp"] +} \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-key-local.json b/tests/SpecTests/client-side-encryption/corpus/corpus-key-local.json index 5da84ab6b..b3fe0723b 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus-key-local.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-key-local.json @@ -1,27 +1,27 @@ { "status": { "$numberInt": "1" - }, + }, "_id": { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } - }, + }, "masterKey": { "provider": "local" - }, + }, "updateDate": { "$date": { "$numberLong": "1557827033449" } - }, + }, "keyMaterial": { "$binary": { - "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", "subType": "00" } - }, + }, "creationDate": { "$date": { "$numberLong": "1557827033449" diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json b/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json index e4838d8aa..f145f712a 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json @@ -34,11 +34,19 @@ }, "aws_double_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_double_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_string_rand_auto_id": { "bsonType": "object", @@ -73,11 +81,19 @@ }, "aws_string_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_string_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_string_det_auto_id": { "bsonType": "object", @@ -100,11 +116,19 @@ }, "aws_string_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_string_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_object_rand_auto_id": { "bsonType": "object", @@ -139,11 +163,19 @@ }, "aws_object_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_object_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_array_rand_auto_id": { "bsonType": "object", @@ -178,11 +210,19 @@ }, "aws_array_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_array_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=00_rand_auto_id": { "bsonType": "object", @@ -217,11 +257,19 @@ }, "aws_binData=00_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=00_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=00_det_auto_id": { "bsonType": "object", @@ -244,11 +292,19 @@ }, "aws_binData=00_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=00_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=04_rand_auto_id": { "bsonType": "object", @@ -283,11 +339,19 @@ }, "aws_binData=04_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=04_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=04_det_auto_id": { "bsonType": "object", @@ -310,11 +374,19 @@ }, "aws_binData=04_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_binData=04_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_objectId_rand_auto_id": { "bsonType": "object", @@ -349,11 +421,19 @@ }, "aws_objectId_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_objectId_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_objectId_det_auto_id": { "bsonType": "object", @@ -376,11 +456,19 @@ }, "aws_objectId_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_objectId_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_bool_rand_auto_id": { "bsonType": "object", @@ -415,11 +503,19 @@ }, "aws_bool_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_bool_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_date_rand_auto_id": { "bsonType": "object", @@ -454,11 +550,19 @@ }, "aws_date_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_date_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_date_det_auto_id": { "bsonType": "object", @@ -481,11 +585,19 @@ }, "aws_date_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_date_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_regex_rand_auto_id": { "bsonType": "object", @@ -520,11 +632,19 @@ }, "aws_regex_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_regex_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_regex_det_auto_id": { "bsonType": "object", @@ -547,11 +667,19 @@ }, "aws_regex_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_regex_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_dbPointer_rand_auto_id": { "bsonType": "object", @@ -586,11 +714,19 @@ }, "aws_dbPointer_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_dbPointer_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_dbPointer_det_auto_id": { "bsonType": "object", @@ -613,11 +749,19 @@ }, "aws_dbPointer_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_dbPointer_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_javascript_rand_auto_id": { "bsonType": "object", @@ -652,11 +796,19 @@ }, "aws_javascript_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_javascript_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_javascript_det_auto_id": { "bsonType": "object", @@ -679,11 +831,19 @@ }, "aws_javascript_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_javascript_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_symbol_rand_auto_id": { "bsonType": "object", @@ -718,11 +878,19 @@ }, "aws_symbol_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_symbol_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_symbol_det_auto_id": { "bsonType": "object", @@ -745,11 +913,19 @@ }, "aws_symbol_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_symbol_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_javascriptWithScope_rand_auto_id": { "bsonType": "object", @@ -784,11 +960,19 @@ }, "aws_javascriptWithScope_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_javascriptWithScope_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_int_rand_auto_id": { "bsonType": "object", @@ -823,11 +1007,19 @@ }, "aws_int_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_int_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_int_det_auto_id": { "bsonType": "object", @@ -850,11 +1042,19 @@ }, "aws_int_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_int_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_timestamp_rand_auto_id": { "bsonType": "object", @@ -889,11 +1089,19 @@ }, "aws_timestamp_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_timestamp_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_timestamp_det_auto_id": { "bsonType": "object", @@ -916,11 +1124,19 @@ }, "aws_timestamp_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_timestamp_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_long_rand_auto_id": { "bsonType": "object", @@ -955,11 +1171,19 @@ }, "aws_long_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_long_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_long_det_auto_id": { "bsonType": "object", @@ -982,11 +1206,19 @@ }, "aws_long_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_long_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_decimal_rand_auto_id": { "bsonType": "object", @@ -1021,11 +1253,19 @@ }, "aws_decimal_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "aws_decimal_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_double_rand_auto_id": { "bsonType": "object", @@ -1060,11 +1300,19 @@ }, "local_double_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_double_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_string_rand_auto_id": { "bsonType": "object", @@ -1099,11 +1347,19 @@ }, "local_string_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_string_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_string_det_auto_id": { "bsonType": "object", @@ -1126,11 +1382,19 @@ }, "local_string_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_string_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_object_rand_auto_id": { "bsonType": "object", @@ -1165,11 +1429,19 @@ }, "local_object_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_object_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_array_rand_auto_id": { "bsonType": "object", @@ -1204,11 +1476,19 @@ }, "local_array_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_array_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=00_rand_auto_id": { "bsonType": "object", @@ -1243,11 +1523,19 @@ }, "local_binData=00_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=00_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=00_det_auto_id": { "bsonType": "object", @@ -1270,11 +1558,19 @@ }, "local_binData=00_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=00_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=04_rand_auto_id": { "bsonType": "object", @@ -1309,11 +1605,19 @@ }, "local_binData=04_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=04_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=04_det_auto_id": { "bsonType": "object", @@ -1336,11 +1640,19 @@ }, "local_binData=04_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_binData=04_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_objectId_rand_auto_id": { "bsonType": "object", @@ -1375,11 +1687,19 @@ }, "local_objectId_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_objectId_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_objectId_det_auto_id": { "bsonType": "object", @@ -1402,11 +1722,19 @@ }, "local_objectId_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_objectId_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_bool_rand_auto_id": { "bsonType": "object", @@ -1441,11 +1769,19 @@ }, "local_bool_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_bool_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_date_rand_auto_id": { "bsonType": "object", @@ -1480,11 +1816,19 @@ }, "local_date_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_date_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_date_det_auto_id": { "bsonType": "object", @@ -1507,11 +1851,19 @@ }, "local_date_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_date_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_regex_rand_auto_id": { "bsonType": "object", @@ -1546,11 +1898,19 @@ }, "local_regex_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_regex_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_regex_det_auto_id": { "bsonType": "object", @@ -1573,11 +1933,19 @@ }, "local_regex_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_regex_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_dbPointer_rand_auto_id": { "bsonType": "object", @@ -1612,11 +1980,19 @@ }, "local_dbPointer_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_dbPointer_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_dbPointer_det_auto_id": { "bsonType": "object", @@ -1639,11 +2015,19 @@ }, "local_dbPointer_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_dbPointer_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_javascript_rand_auto_id": { "bsonType": "object", @@ -1678,11 +2062,19 @@ }, "local_javascript_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_javascript_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_javascript_det_auto_id": { "bsonType": "object", @@ -1705,11 +2097,19 @@ }, "local_javascript_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_javascript_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_symbol_rand_auto_id": { "bsonType": "object", @@ -1744,11 +2144,19 @@ }, "local_symbol_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_symbol_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_symbol_det_auto_id": { "bsonType": "object", @@ -1771,11 +2179,19 @@ }, "local_symbol_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_symbol_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_javascriptWithScope_rand_auto_id": { "bsonType": "object", @@ -1810,11 +2226,19 @@ }, "local_javascriptWithScope_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_javascriptWithScope_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_int_rand_auto_id": { "bsonType": "object", @@ -1849,11 +2273,19 @@ }, "local_int_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_int_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_int_det_auto_id": { "bsonType": "object", @@ -1876,11 +2308,19 @@ }, "local_int_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_int_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_timestamp_rand_auto_id": { "bsonType": "object", @@ -1915,11 +2355,19 @@ }, "local_timestamp_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_timestamp_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_timestamp_det_auto_id": { "bsonType": "object", @@ -1942,11 +2390,19 @@ }, "local_timestamp_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_timestamp_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_long_rand_auto_id": { "bsonType": "object", @@ -1981,11 +2437,19 @@ }, "local_long_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_long_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_long_det_auto_id": { "bsonType": "object", @@ -2008,11 +2472,19 @@ }, "local_long_det_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_long_det_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_decimal_rand_auto_id": { "bsonType": "object", @@ -2047,11 +2519,2551 @@ }, "local_decimal_rand_explicit_id": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } }, "local_decimal_rand_explicit_altname": { "bsonType": "object", - "properties": { "value": { "bsonType": "binData" } } + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_double_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "azure_double_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "azure_double_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_double_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_string_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "azure_string_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "azure_string_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_string_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_string_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "string" + } + } + } + }, + "azure_string_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_string_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_object_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "azure_object_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "azure_object_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_object_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_array_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "azure_array_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "azure_array_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_array_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=00_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "azure_binData=00_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "azure_binData=00_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=00_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=00_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "azure_binData=00_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=00_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=04_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "azure_binData=04_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "azure_binData=04_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=04_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=04_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "azure_binData=04_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_binData=04_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_objectId_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "azure_objectId_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "azure_objectId_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_objectId_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_objectId_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "objectId" + } + } + } + }, + "azure_objectId_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_objectId_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_bool_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "azure_bool_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "azure_bool_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_bool_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_date_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "azure_date_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "azure_date_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_date_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_date_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "date" + } + } + } + }, + "azure_date_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_date_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_regex_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "azure_regex_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "azure_regex_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_regex_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_regex_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "regex" + } + } + } + }, + "azure_regex_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_regex_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_dbPointer_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "azure_dbPointer_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "azure_dbPointer_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_dbPointer_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_dbPointer_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "dbPointer" + } + } + } + }, + "azure_dbPointer_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_dbPointer_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_javascript_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "azure_javascript_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "azure_javascript_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_javascript_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_javascript_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "javascript" + } + } + } + }, + "azure_javascript_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_javascript_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_symbol_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "azure_symbol_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "azure_symbol_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_symbol_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_symbol_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "symbol" + } + } + } + }, + "azure_symbol_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_symbol_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_javascriptWithScope_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "azure_javascriptWithScope_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "azure_javascriptWithScope_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_javascriptWithScope_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_int_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "azure_int_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "azure_int_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_int_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_int_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "int" + } + } + } + }, + "azure_int_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_int_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_timestamp_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "azure_timestamp_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "azure_timestamp_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_timestamp_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_timestamp_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "timestamp" + } + } + } + }, + "azure_timestamp_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_timestamp_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_long_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "azure_long_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "azure_long_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_long_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_long_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "long" + } + } + } + }, + "azure_long_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_long_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_decimal_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZUREAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "azure_decimal_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_azure", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "azure_decimal_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "azure_decimal_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_double_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "gcp_double_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "gcp_double_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_double_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_string_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "gcp_string_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "gcp_string_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_string_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_string_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "string" + } + } + } + }, + "gcp_string_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_string_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_object_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "gcp_object_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "gcp_object_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_object_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_array_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "gcp_array_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "gcp_array_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_array_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=00_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "gcp_binData=00_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "gcp_binData=00_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=00_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=00_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "gcp_binData=00_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=00_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=04_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "gcp_binData=04_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "gcp_binData=04_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=04_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=04_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "gcp_binData=04_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_binData=04_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_objectId_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "gcp_objectId_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "gcp_objectId_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_objectId_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_objectId_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "objectId" + } + } + } + }, + "gcp_objectId_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_objectId_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_bool_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "gcp_bool_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "gcp_bool_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_bool_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_date_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "gcp_date_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "gcp_date_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_date_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_date_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "date" + } + } + } + }, + "gcp_date_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_date_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_regex_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "gcp_regex_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "gcp_regex_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_regex_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_regex_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "regex" + } + } + } + }, + "gcp_regex_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_regex_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_dbPointer_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "gcp_dbPointer_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "gcp_dbPointer_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_dbPointer_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_dbPointer_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "dbPointer" + } + } + } + }, + "gcp_dbPointer_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_dbPointer_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_javascript_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "gcp_javascript_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "gcp_javascript_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_javascript_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_javascript_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "javascript" + } + } + } + }, + "gcp_javascript_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_javascript_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_symbol_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "gcp_symbol_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "gcp_symbol_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_symbol_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_symbol_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "symbol" + } + } + } + }, + "gcp_symbol_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_symbol_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_javascriptWithScope_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "gcp_javascriptWithScope_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "gcp_javascriptWithScope_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_javascriptWithScope_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_int_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "gcp_int_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "gcp_int_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_int_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_int_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "int" + } + } + } + }, + "gcp_int_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_int_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_timestamp_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "gcp_timestamp_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "gcp_timestamp_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_timestamp_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_timestamp_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "timestamp" + } + } + } + }, + "gcp_timestamp_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_timestamp_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_long_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "gcp_long_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "gcp_long_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_long_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_long_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "long" + } + } + } + }, + "gcp_long_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_long_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_decimal_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCPAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "gcp_decimal_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_gcp", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "gcp_decimal_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "gcp_decimal_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } } } -} +} \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus.json b/tests/SpecTests/client-side-encryption/corpus/corpus.json index cbf7a091a..55bbaf99c 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus.json @@ -2,6 +2,8 @@ "_id": "client_side_encryption_corpus", "altname_aws": "aws", "altname_local": "local", + "altname_azure": "azure", + "altname_gcp": "gcp", "aws_double_rand_auto_id": { "kms": "aws", "type": "double", @@ -9,7 +11,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "aws_double_rand_auto_altname": { "kms": "aws", @@ -18,7 +22,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "aws_double_rand_explicit_id": { "kms": "aws", @@ -27,7 +33,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "aws_double_rand_explicit_altname": { "kms": "aws", @@ -36,7 +44,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "aws_double_det_explicit_id": { "kms": "aws", @@ -45,7 +55,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "aws_double_det_explicit_altname": { "kms": "aws", @@ -54,7 +66,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "aws_string_rand_auto_id": { "kms": "aws", @@ -126,7 +140,11 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "aws_object_rand_auto_altname": { "kms": "aws", @@ -135,7 +153,11 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "aws_object_rand_explicit_id": { "kms": "aws", @@ -144,7 +166,11 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "aws_object_rand_explicit_altname": { "kms": "aws", @@ -153,7 +179,11 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "aws_object_det_explicit_id": { "kms": "aws", @@ -162,7 +192,11 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "aws_object_det_explicit_altname": { "kms": "aws", @@ -171,7 +205,11 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "aws_array_rand_auto_id": { "kms": "aws", @@ -181,9 +219,15 @@ "identifier": "id", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "aws_array_rand_auto_altname": { @@ -194,9 +238,15 @@ "identifier": "altname", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "aws_array_rand_explicit_id": { @@ -207,9 +257,15 @@ "identifier": "id", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "aws_array_rand_explicit_altname": { @@ -220,9 +276,15 @@ "identifier": "altname", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "aws_array_det_explicit_id": { @@ -233,9 +295,15 @@ "identifier": "id", "allowed": false, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "aws_array_det_explicit_altname": { @@ -246,9 +314,15 @@ "identifier": "altname", "allowed": false, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "aws_binData=00_rand_auto_id": { @@ -258,7 +332,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=00_rand_auto_altname": { "kms": "aws", @@ -267,7 +346,12 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=00_rand_explicit_id": { "kms": "aws", @@ -276,7 +360,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=00_rand_explicit_altname": { "kms": "aws", @@ -285,7 +374,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=00_det_auto_id": { "kms": "aws", @@ -294,7 +388,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=00_det_explicit_id": { "kms": "aws", @@ -303,7 +402,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=00_det_explicit_altname": { "kms": "aws", @@ -312,7 +416,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "aws_binData=04_rand_auto_id": { "kms": "aws", @@ -322,7 +431,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_binData=04_rand_auto_altname": { @@ -333,7 +445,10 @@ "identifier": "altname", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_binData=04_rand_explicit_id": { @@ -344,7 +459,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_binData=04_rand_explicit_altname": { @@ -355,7 +473,10 @@ "identifier": "altname", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_binData=04_det_auto_id": { @@ -366,7 +487,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_binData=04_det_explicit_id": { @@ -377,7 +501,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_binData=04_det_explicit_altname": { @@ -388,7 +515,10 @@ "identifier": "altname", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "aws_undefined_rand_explicit_id": { @@ -398,7 +528,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "aws_undefined_rand_explicit_altname": { "kms": "aws", @@ -407,7 +539,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "aws_undefined_det_explicit_id": { "kms": "aws", @@ -416,7 +550,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "aws_undefined_det_explicit_altname": { "kms": "aws", @@ -425,7 +561,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "aws_objectId_rand_auto_id": { "kms": "aws", @@ -434,7 +572,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_objectId_rand_auto_altname": { "kms": "aws", @@ -443,7 +583,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_objectId_rand_explicit_id": { "kms": "aws", @@ -452,7 +594,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_objectId_rand_explicit_altname": { "kms": "aws", @@ -461,7 +605,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_objectId_det_auto_id": { "kms": "aws", @@ -470,7 +616,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_objectId_det_explicit_id": { "kms": "aws", @@ -479,7 +627,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_objectId_det_explicit_altname": { "kms": "aws", @@ -488,7 +638,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "aws_bool_rand_auto_id": { "kms": "aws", @@ -551,7 +703,11 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_date_rand_auto_altname": { "kms": "aws", @@ -560,7 +716,11 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_date_rand_explicit_id": { "kms": "aws", @@ -569,7 +729,11 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_date_rand_explicit_altname": { "kms": "aws", @@ -578,7 +742,11 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_date_det_auto_id": { "kms": "aws", @@ -587,7 +755,11 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_date_det_explicit_id": { "kms": "aws", @@ -596,7 +768,11 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_date_det_explicit_altname": { "kms": "aws", @@ -605,7 +781,11 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "aws_null_rand_explicit_id": { "kms": "aws", @@ -650,7 +830,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_regex_rand_auto_altname": { "kms": "aws", @@ -659,7 +844,12 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_regex_rand_explicit_id": { "kms": "aws", @@ -668,7 +858,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_regex_rand_explicit_altname": { "kms": "aws", @@ -677,7 +872,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_regex_det_auto_id": { "kms": "aws", @@ -686,7 +886,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_regex_det_explicit_id": { "kms": "aws", @@ -695,7 +900,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_regex_det_explicit_altname": { "kms": "aws", @@ -704,7 +914,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "aws_dbPointer_rand_auto_id": { "kms": "aws", @@ -716,7 +931,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -730,7 +947,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -744,7 +963,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -758,7 +979,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -772,7 +995,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -786,7 +1011,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -800,7 +1027,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -811,7 +1040,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_javascript_rand_auto_altname": { "kms": "aws", @@ -820,7 +1051,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_javascript_rand_explicit_id": { "kms": "aws", @@ -829,7 +1062,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_javascript_rand_explicit_altname": { "kms": "aws", @@ -838,7 +1073,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_javascript_det_auto_id": { "kms": "aws", @@ -847,7 +1084,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_javascript_det_explicit_id": { "kms": "aws", @@ -856,7 +1095,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_javascript_det_explicit_altname": { "kms": "aws", @@ -865,7 +1106,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "aws_symbol_rand_auto_id": { "kms": "aws", @@ -874,7 +1117,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_symbol_rand_auto_altname": { "kms": "aws", @@ -883,7 +1128,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_symbol_rand_explicit_id": { "kms": "aws", @@ -892,7 +1139,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_symbol_rand_explicit_altname": { "kms": "aws", @@ -901,7 +1150,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_symbol_det_auto_id": { "kms": "aws", @@ -910,7 +1161,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_symbol_det_explicit_id": { "kms": "aws", @@ -919,7 +1172,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_symbol_det_explicit_altname": { "kms": "aws", @@ -928,7 +1183,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "aws_javascriptWithScope_rand_auto_id": { "kms": "aws", @@ -937,7 +1194,10 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "aws_javascriptWithScope_rand_auto_altname": { "kms": "aws", @@ -946,7 +1206,10 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "aws_javascriptWithScope_rand_explicit_id": { "kms": "aws", @@ -955,7 +1218,10 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "aws_javascriptWithScope_rand_explicit_altname": { "kms": "aws", @@ -964,7 +1230,10 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "aws_javascriptWithScope_det_explicit_id": { "kms": "aws", @@ -973,7 +1242,10 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "aws_javascriptWithScope_det_explicit_altname": { "kms": "aws", @@ -982,7 +1254,10 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "aws_int_rand_auto_id": { "kms": "aws", @@ -991,7 +1266,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_int_rand_auto_altname": { "kms": "aws", @@ -1000,7 +1277,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_int_rand_explicit_id": { "kms": "aws", @@ -1009,7 +1288,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_int_rand_explicit_altname": { "kms": "aws", @@ -1018,7 +1299,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_int_det_auto_id": { "kms": "aws", @@ -1027,7 +1310,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_int_det_explicit_id": { "kms": "aws", @@ -1036,7 +1321,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_int_det_explicit_altname": { "kms": "aws", @@ -1045,7 +1332,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "aws_timestamp_rand_auto_id": { "kms": "aws", @@ -1054,7 +1343,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_timestamp_rand_auto_altname": { "kms": "aws", @@ -1063,7 +1357,12 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_timestamp_rand_explicit_id": { "kms": "aws", @@ -1072,7 +1371,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_timestamp_rand_explicit_altname": { "kms": "aws", @@ -1081,7 +1385,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_timestamp_det_auto_id": { "kms": "aws", @@ -1090,7 +1399,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_timestamp_det_explicit_id": { "kms": "aws", @@ -1099,7 +1413,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_timestamp_det_explicit_altname": { "kms": "aws", @@ -1108,7 +1427,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "aws_long_rand_auto_id": { "kms": "aws", @@ -1117,7 +1441,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_long_rand_auto_altname": { "kms": "aws", @@ -1126,7 +1452,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_long_rand_explicit_id": { "kms": "aws", @@ -1135,7 +1463,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_long_rand_explicit_altname": { "kms": "aws", @@ -1144,7 +1474,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_long_det_auto_id": { "kms": "aws", @@ -1153,7 +1485,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_long_det_explicit_id": { "kms": "aws", @@ -1162,7 +1496,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_long_det_explicit_altname": { "kms": "aws", @@ -1171,7 +1507,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "aws_decimal_rand_auto_id": { "kms": "aws", @@ -1180,7 +1518,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "aws_decimal_rand_auto_altname": { "kms": "aws", @@ -1189,7 +1529,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "aws_decimal_rand_explicit_id": { "kms": "aws", @@ -1198,7 +1540,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "aws_decimal_rand_explicit_altname": { "kms": "aws", @@ -1207,7 +1551,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "aws_decimal_det_explicit_id": { "kms": "aws", @@ -1216,7 +1562,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "aws_decimal_det_explicit_altname": { "kms": "aws", @@ -1225,7 +1573,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "aws_minKey_rand_explicit_id": { "kms": "aws", @@ -1234,7 +1584,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "aws_minKey_rand_explicit_altname": { "kms": "aws", @@ -1243,7 +1595,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "aws_minKey_det_explicit_id": { "kms": "aws", @@ -1252,7 +1606,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "aws_minKey_det_explicit_altname": { "kms": "aws", @@ -1261,7 +1617,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "aws_maxKey_rand_explicit_id": { "kms": "aws", @@ -1270,7 +1628,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "aws_maxKey_rand_explicit_altname": { "kms": "aws", @@ -1279,7 +1639,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "aws_maxKey_det_explicit_id": { "kms": "aws", @@ -1288,7 +1650,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "aws_maxKey_det_explicit_altname": { "kms": "aws", @@ -1297,7 +1661,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "local_double_rand_auto_id": { "kms": "local", @@ -1306,7 +1672,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "local_double_rand_auto_altname": { "kms": "local", @@ -1315,7 +1683,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "local_double_rand_explicit_id": { "kms": "local", @@ -1324,7 +1694,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "local_double_rand_explicit_altname": { "kms": "local", @@ -1333,7 +1705,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "local_double_det_explicit_id": { "kms": "local", @@ -1342,7 +1716,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$numberDouble": "1.234" } + "value": { + "$numberDouble": "1.234" + } }, "local_double_det_explicit_altname": { "kms": "local", @@ -1351,8 +1727,10 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$numberDouble": "1.234" } - }, + "value": { + "$numberDouble": "1.234" + } + }, "local_string_rand_auto_id": { "kms": "local", "type": "string", @@ -1423,7 +1801,11 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "local_object_rand_auto_altname": { "kms": "local", @@ -1432,7 +1814,11 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "local_object_rand_explicit_id": { "kms": "local", @@ -1441,7 +1827,11 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "local_object_rand_explicit_altname": { "kms": "local", @@ -1450,7 +1840,11 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "local_object_det_explicit_id": { "kms": "local", @@ -1459,7 +1853,11 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "local_object_det_explicit_altname": { "kms": "local", @@ -1468,7 +1866,11 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "x": { "$numberInt": "1" } } + "value": { + "x": { + "$numberInt": "1" + } + } }, "local_array_rand_auto_id": { "kms": "local", @@ -1478,9 +1880,15 @@ "identifier": "id", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "local_array_rand_auto_altname": { @@ -1491,9 +1899,15 @@ "identifier": "altname", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "local_array_rand_explicit_id": { @@ -1504,9 +1918,15 @@ "identifier": "id", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "local_array_rand_explicit_altname": { @@ -1517,9 +1937,15 @@ "identifier": "altname", "allowed": true, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "local_array_det_explicit_id": { @@ -1530,9 +1956,15 @@ "identifier": "id", "allowed": false, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "local_array_det_explicit_altname": { @@ -1543,9 +1975,15 @@ "identifier": "altname", "allowed": false, "value": [ - { "$numberInt": "1" }, - { "$numberInt": "2" }, - { "$numberInt": "3" } + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } ] }, "local_binData=00_rand_auto_id": { @@ -1555,7 +1993,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=00_rand_auto_altname": { "kms": "local", @@ -1564,7 +2007,12 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=00_rand_explicit_id": { "kms": "local", @@ -1573,7 +2021,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=00_rand_explicit_altname": { "kms": "local", @@ -1582,7 +2035,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=00_det_auto_id": { "kms": "local", @@ -1591,7 +2049,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=00_det_explicit_id": { "kms": "local", @@ -1600,7 +2063,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=00_det_explicit_altname": { "kms": "local", @@ -1609,7 +2077,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$binary": { "base64": "AQIDBA==", "subType": "00" } } + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } }, "local_binData=04_rand_auto_id": { "kms": "local", @@ -1619,7 +2092,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_binData=04_rand_auto_altname": { @@ -1630,7 +2106,10 @@ "identifier": "altname", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_binData=04_rand_explicit_id": { @@ -1641,7 +2120,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_binData=04_rand_explicit_altname": { @@ -1652,7 +2134,10 @@ "identifier": "altname", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_binData=04_det_auto_id": { @@ -1663,7 +2148,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_binData=04_det_explicit_id": { @@ -1674,7 +2162,10 @@ "identifier": "id", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_binData=04_det_explicit_altname": { @@ -1685,7 +2176,10 @@ "identifier": "altname", "allowed": true, "value": { - "$binary": { "base64": "AAECAwQFBgcICQoLDA0ODw==", "subType": "04" } + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } } }, "local_undefined_rand_explicit_id": { @@ -1695,7 +2189,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "local_undefined_rand_explicit_altname": { "kms": "local", @@ -1704,7 +2200,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "local_undefined_det_explicit_id": { "kms": "local", @@ -1713,7 +2211,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "local_undefined_det_explicit_altname": { "kms": "local", @@ -1722,7 +2222,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$undefined": true } + "value": { + "$undefined": true + } }, "local_objectId_rand_auto_id": { "kms": "local", @@ -1731,7 +2233,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_objectId_rand_auto_altname": { "kms": "local", @@ -1740,7 +2244,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_objectId_rand_explicit_id": { "kms": "local", @@ -1749,7 +2255,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_objectId_rand_explicit_altname": { "kms": "local", @@ -1758,7 +2266,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_objectId_det_auto_id": { "kms": "local", @@ -1767,7 +2277,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_objectId_det_explicit_id": { "kms": "local", @@ -1776,7 +2288,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_objectId_det_explicit_altname": { "kms": "local", @@ -1785,7 +2299,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$oid": "01234567890abcdef0123456" } + "value": { + "$oid": "01234567890abcdef0123456" + } }, "local_bool_rand_auto_id": { "kms": "local", @@ -1848,7 +2364,11 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_date_rand_auto_altname": { "kms": "local", @@ -1857,7 +2377,11 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_date_rand_explicit_id": { "kms": "local", @@ -1866,7 +2390,11 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_date_rand_explicit_altname": { "kms": "local", @@ -1875,7 +2403,11 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_date_det_auto_id": { "kms": "local", @@ -1884,7 +2416,11 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_date_det_explicit_id": { "kms": "local", @@ -1893,7 +2429,11 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_date_det_explicit_altname": { "kms": "local", @@ -1902,7 +2442,11 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$date": { "$numberLong": "12345" } } + "value": { + "$date": { + "$numberLong": "12345" + } + } }, "local_null_rand_explicit_id": { "kms": "local", @@ -1947,7 +2491,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_regex_rand_auto_altname": { "kms": "local", @@ -1956,7 +2505,12 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_regex_rand_explicit_id": { "kms": "local", @@ -1965,7 +2519,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_regex_rand_explicit_altname": { "kms": "local", @@ -1974,7 +2533,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_regex_det_auto_id": { "kms": "local", @@ -1983,7 +2547,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_regex_det_explicit_id": { "kms": "local", @@ -1992,7 +2561,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_regex_det_explicit_altname": { "kms": "local", @@ -2001,7 +2575,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$regularExpression": { "pattern": ".*", "options": "" } } + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } }, "local_dbPointer_rand_auto_id": { "kms": "local", @@ -2013,7 +2592,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2027,7 +2608,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2041,7 +2624,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2055,7 +2640,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2069,7 +2656,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2083,7 +2672,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2097,7 +2688,9 @@ "value": { "$dbPointer": { "$ref": "db.example", - "$id": { "$oid": "01234567890abcdef0123456" } + "$id": { + "$oid": "01234567890abcdef0123456" + } } } }, @@ -2108,7 +2701,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_javascript_rand_auto_altname": { "kms": "local", @@ -2117,7 +2712,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_javascript_rand_explicit_id": { "kms": "local", @@ -2126,7 +2723,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_javascript_rand_explicit_altname": { "kms": "local", @@ -2135,7 +2734,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_javascript_det_auto_id": { "kms": "local", @@ -2144,7 +2745,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_javascript_det_explicit_id": { "kms": "local", @@ -2153,7 +2756,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_javascript_det_explicit_altname": { "kms": "local", @@ -2162,7 +2767,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1" } + "value": { + "$code": "x=1" + } }, "local_symbol_rand_auto_id": { "kms": "local", @@ -2171,7 +2778,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_symbol_rand_auto_altname": { "kms": "local", @@ -2180,7 +2789,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_symbol_rand_explicit_id": { "kms": "local", @@ -2189,7 +2800,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_symbol_rand_explicit_altname": { "kms": "local", @@ -2198,7 +2811,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_symbol_det_auto_id": { "kms": "local", @@ -2207,7 +2822,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_symbol_det_explicit_id": { "kms": "local", @@ -2216,7 +2833,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_symbol_det_explicit_altname": { "kms": "local", @@ -2225,7 +2844,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$symbol": "mongodb-symbol" } + "value": { + "$symbol": "mongodb-symbol" + } }, "local_javascriptWithScope_rand_auto_id": { "kms": "local", @@ -2234,7 +2855,10 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "local_javascriptWithScope_rand_auto_altname": { "kms": "local", @@ -2243,7 +2867,10 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "local_javascriptWithScope_rand_explicit_id": { "kms": "local", @@ -2252,7 +2879,10 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "local_javascriptWithScope_rand_explicit_altname": { "kms": "local", @@ -2261,7 +2891,10 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "local_javascriptWithScope_det_explicit_id": { "kms": "local", @@ -2270,7 +2903,10 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "local_javascriptWithScope_det_explicit_altname": { "kms": "local", @@ -2279,7 +2915,10 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$code": "x=1", "$scope": {} } + "value": { + "$code": "x=1", + "$scope": {} + } }, "local_int_rand_auto_id": { "kms": "local", @@ -2288,7 +2927,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_int_rand_auto_altname": { "kms": "local", @@ -2297,7 +2938,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_int_rand_explicit_id": { "kms": "local", @@ -2306,7 +2949,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_int_rand_explicit_altname": { "kms": "local", @@ -2315,7 +2960,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_int_det_auto_id": { "kms": "local", @@ -2324,7 +2971,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_int_det_explicit_id": { "kms": "local", @@ -2333,7 +2982,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_int_det_explicit_altname": { "kms": "local", @@ -2342,7 +2993,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberInt": "123" } + "value": { + "$numberInt": "123" + } }, "local_timestamp_rand_auto_id": { "kms": "local", @@ -2351,7 +3004,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_timestamp_rand_auto_altname": { "kms": "local", @@ -2360,7 +3018,12 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_timestamp_rand_explicit_id": { "kms": "local", @@ -2369,7 +3032,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_timestamp_rand_explicit_altname": { "kms": "local", @@ -2378,7 +3046,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_timestamp_det_auto_id": { "kms": "local", @@ -2387,7 +3060,12 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_timestamp_det_explicit_id": { "kms": "local", @@ -2396,7 +3074,12 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_timestamp_det_explicit_altname": { "kms": "local", @@ -2405,7 +3088,12 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$timestamp": { "t": 0, "i": 12345 } } + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } }, "local_long_rand_auto_id": { "kms": "local", @@ -2414,7 +3102,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_long_rand_auto_altname": { "kms": "local", @@ -2423,7 +3113,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_long_rand_explicit_id": { "kms": "local", @@ -2432,7 +3124,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_long_rand_explicit_altname": { "kms": "local", @@ -2441,7 +3135,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_long_det_auto_id": { "kms": "local", @@ -2450,7 +3146,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_long_det_explicit_id": { "kms": "local", @@ -2459,7 +3157,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_long_det_explicit_altname": { "kms": "local", @@ -2468,7 +3168,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberLong": "456" } + "value": { + "$numberLong": "456" + } }, "local_decimal_rand_auto_id": { "kms": "local", @@ -2477,7 +3179,9 @@ "method": "auto", "identifier": "id", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "local_decimal_rand_auto_altname": { "kms": "local", @@ -2486,7 +3190,9 @@ "method": "auto", "identifier": "altname", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "local_decimal_rand_explicit_id": { "kms": "local", @@ -2495,7 +3201,9 @@ "method": "explicit", "identifier": "id", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "local_decimal_rand_explicit_altname": { "kms": "local", @@ -2504,7 +3212,9 @@ "method": "explicit", "identifier": "altname", "allowed": true, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "local_decimal_det_explicit_id": { "kms": "local", @@ -2513,7 +3223,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "local_decimal_det_explicit_altname": { "kms": "local", @@ -2522,7 +3234,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$numberDecimal": "1.234" } + "value": { + "$numberDecimal": "1.234" + } }, "local_minKey_rand_explicit_id": { "kms": "local", @@ -2531,7 +3245,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "local_minKey_rand_explicit_altname": { "kms": "local", @@ -2540,7 +3256,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "local_minKey_det_explicit_id": { "kms": "local", @@ -2549,7 +3267,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "local_minKey_det_explicit_altname": { "kms": "local", @@ -2558,7 +3278,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$minKey": 1 } + "value": { + "$minKey": 1 + } }, "local_maxKey_rand_explicit_id": { "kms": "local", @@ -2567,7 +3289,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "local_maxKey_rand_explicit_altname": { "kms": "local", @@ -2576,7 +3300,9 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "local_maxKey_det_explicit_id": { "kms": "local", @@ -2585,7 +3311,9 @@ "method": "explicit", "identifier": "id", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } }, "local_maxKey_det_explicit_altname": { "kms": "local", @@ -2594,7 +3322,3331 @@ "method": "explicit", "identifier": "altname", "allowed": false, - "value": { "$maxKey": 1 } + "value": { + "$maxKey": 1 + } + }, + "azure_double_rand_auto_id": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "azure_double_rand_auto_altname": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "azure_double_rand_explicit_id": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "azure_double_rand_explicit_altname": { + "kms": "azure", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "azure_double_det_explicit_id": { + "kms": "azure", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "azure_double_det_explicit_altname": { + "kms": "azure", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "azure_string_rand_auto_id": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "azure_string_rand_auto_altname": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "azure_string_rand_explicit_id": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "azure_string_rand_explicit_altname": { + "kms": "azure", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "azure_string_det_auto_id": { + "kms": "azure", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "azure_string_det_explicit_id": { + "kms": "azure", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "azure_string_det_explicit_altname": { + "kms": "azure", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "azure_object_rand_auto_id": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_object_rand_auto_altname": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_object_rand_explicit_id": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_object_rand_explicit_altname": { + "kms": "azure", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_object_det_explicit_id": { + "kms": "azure", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_object_det_explicit_altname": { + "kms": "azure", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "azure_array_rand_auto_id": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_array_rand_auto_altname": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_array_rand_explicit_id": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_array_rand_explicit_altname": { + "kms": "azure", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_array_det_explicit_id": { + "kms": "azure", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_array_det_explicit_altname": { + "kms": "azure", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "azure_binData=00_rand_auto_id": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=00_rand_auto_altname": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=00_rand_explicit_id": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=00_rand_explicit_altname": { + "kms": "azure", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=00_det_auto_id": { + "kms": "azure", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=00_det_explicit_id": { + "kms": "azure", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=00_det_explicit_altname": { + "kms": "azure", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "azure_binData=04_rand_auto_id": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_binData=04_rand_auto_altname": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_binData=04_rand_explicit_id": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_binData=04_rand_explicit_altname": { + "kms": "azure", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_binData=04_det_auto_id": { + "kms": "azure", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_binData=04_det_explicit_id": { + "kms": "azure", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_binData=04_det_explicit_altname": { + "kms": "azure", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "azure_undefined_rand_explicit_id": { + "kms": "azure", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_undefined_rand_explicit_altname": { + "kms": "azure", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_undefined_det_explicit_id": { + "kms": "azure", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_undefined_det_explicit_altname": { + "kms": "azure", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "azure_objectId_rand_auto_id": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_objectId_rand_auto_altname": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_objectId_rand_explicit_id": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_objectId_rand_explicit_altname": { + "kms": "azure", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_objectId_det_auto_id": { + "kms": "azure", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_objectId_det_explicit_id": { + "kms": "azure", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_objectId_det_explicit_altname": { + "kms": "azure", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "azure_bool_rand_auto_id": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": true + }, + "azure_bool_rand_auto_altname": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": true + }, + "azure_bool_rand_explicit_id": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": true + }, + "azure_bool_rand_explicit_altname": { + "kms": "azure", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": true + }, + "azure_bool_det_explicit_id": { + "kms": "azure", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "azure_bool_det_explicit_altname": { + "kms": "azure", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "azure_date_rand_auto_id": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_date_rand_auto_altname": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_date_rand_explicit_id": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_date_rand_explicit_altname": { + "kms": "azure", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_date_det_auto_id": { + "kms": "azure", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_date_det_explicit_id": { + "kms": "azure", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_date_det_explicit_altname": { + "kms": "azure", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "azure_null_rand_explicit_id": { + "kms": "azure", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "azure_null_rand_explicit_altname": { + "kms": "azure", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "azure_null_det_explicit_id": { + "kms": "azure", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "azure_null_det_explicit_altname": { + "kms": "azure", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "azure_regex_rand_auto_id": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_regex_rand_auto_altname": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_regex_rand_explicit_id": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_regex_rand_explicit_altname": { + "kms": "azure", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_regex_det_auto_id": { + "kms": "azure", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_regex_det_explicit_id": { + "kms": "azure", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_regex_det_explicit_altname": { + "kms": "azure", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "azure_dbPointer_rand_auto_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_dbPointer_rand_auto_altname": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_dbPointer_rand_explicit_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_dbPointer_rand_explicit_altname": { + "kms": "azure", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_dbPointer_det_auto_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_dbPointer_det_explicit_id": { + "kms": "azure", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_dbPointer_det_explicit_altname": { + "kms": "azure", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "azure_javascript_rand_auto_id": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_javascript_rand_auto_altname": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_javascript_rand_explicit_id": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_javascript_rand_explicit_altname": { + "kms": "azure", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_javascript_det_auto_id": { + "kms": "azure", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_javascript_det_explicit_id": { + "kms": "azure", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_javascript_det_explicit_altname": { + "kms": "azure", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "azure_symbol_rand_auto_id": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_symbol_rand_auto_altname": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_symbol_rand_explicit_id": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_symbol_rand_explicit_altname": { + "kms": "azure", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_symbol_det_auto_id": { + "kms": "azure", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_symbol_det_explicit_id": { + "kms": "azure", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_symbol_det_explicit_altname": { + "kms": "azure", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "azure_javascriptWithScope_rand_auto_id": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_javascriptWithScope_rand_auto_altname": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_javascriptWithScope_rand_explicit_id": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_javascriptWithScope_rand_explicit_altname": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_javascriptWithScope_det_explicit_id": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_javascriptWithScope_det_explicit_altname": { + "kms": "azure", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "azure_int_rand_auto_id": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_int_rand_auto_altname": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_int_rand_explicit_id": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_int_rand_explicit_altname": { + "kms": "azure", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_int_det_auto_id": { + "kms": "azure", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_int_det_explicit_id": { + "kms": "azure", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_int_det_explicit_altname": { + "kms": "azure", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "azure_timestamp_rand_auto_id": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_timestamp_rand_auto_altname": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_timestamp_rand_explicit_id": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_timestamp_rand_explicit_altname": { + "kms": "azure", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_timestamp_det_auto_id": { + "kms": "azure", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_timestamp_det_explicit_id": { + "kms": "azure", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_timestamp_det_explicit_altname": { + "kms": "azure", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "azure_long_rand_auto_id": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_long_rand_auto_altname": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_long_rand_explicit_id": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_long_rand_explicit_altname": { + "kms": "azure", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_long_det_auto_id": { + "kms": "azure", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_long_det_explicit_id": { + "kms": "azure", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_long_det_explicit_altname": { + "kms": "azure", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "azure_decimal_rand_auto_id": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_decimal_rand_auto_altname": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_decimal_rand_explicit_id": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_decimal_rand_explicit_altname": { + "kms": "azure", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_decimal_det_explicit_id": { + "kms": "azure", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_decimal_det_explicit_altname": { + "kms": "azure", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "azure_minKey_rand_explicit_id": { + "kms": "azure", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_minKey_rand_explicit_altname": { + "kms": "azure", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_minKey_det_explicit_id": { + "kms": "azure", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_minKey_det_explicit_altname": { + "kms": "azure", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "azure_maxKey_rand_explicit_id": { + "kms": "azure", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "azure_maxKey_rand_explicit_altname": { + "kms": "azure", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "azure_maxKey_det_explicit_id": { + "kms": "azure", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "azure_maxKey_det_explicit_altname": { + "kms": "azure", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_double_rand_auto_id": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "gcp_double_rand_auto_altname": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "gcp_double_rand_explicit_id": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "gcp_double_rand_explicit_altname": { + "kms": "gcp", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "gcp_double_det_explicit_id": { + "kms": "gcp", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "gcp_double_det_explicit_altname": { + "kms": "gcp", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "gcp_string_rand_auto_id": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "gcp_string_rand_auto_altname": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "gcp_string_rand_explicit_id": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "gcp_string_rand_explicit_altname": { + "kms": "gcp", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "gcp_string_det_auto_id": { + "kms": "gcp", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "gcp_string_det_explicit_id": { + "kms": "gcp", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "gcp_string_det_explicit_altname": { + "kms": "gcp", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "gcp_object_rand_auto_id": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_object_rand_auto_altname": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_object_rand_explicit_id": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_object_rand_explicit_altname": { + "kms": "gcp", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_object_det_explicit_id": { + "kms": "gcp", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_object_det_explicit_altname": { + "kms": "gcp", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "gcp_array_rand_auto_id": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_array_rand_auto_altname": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_array_rand_explicit_id": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_array_rand_explicit_altname": { + "kms": "gcp", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_array_det_explicit_id": { + "kms": "gcp", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_array_det_explicit_altname": { + "kms": "gcp", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "gcp_binData=00_rand_auto_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=00_rand_auto_altname": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=00_rand_explicit_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=00_rand_explicit_altname": { + "kms": "gcp", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=00_det_auto_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=00_det_explicit_id": { + "kms": "gcp", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=00_det_explicit_altname": { + "kms": "gcp", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "gcp_binData=04_rand_auto_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_binData=04_rand_auto_altname": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_binData=04_rand_explicit_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_binData=04_rand_explicit_altname": { + "kms": "gcp", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_binData=04_det_auto_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_binData=04_det_explicit_id": { + "kms": "gcp", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_binData=04_det_explicit_altname": { + "kms": "gcp", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "gcp_undefined_rand_explicit_id": { + "kms": "gcp", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_undefined_rand_explicit_altname": { + "kms": "gcp", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_undefined_det_explicit_id": { + "kms": "gcp", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_undefined_det_explicit_altname": { + "kms": "gcp", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "gcp_objectId_rand_auto_id": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_objectId_rand_auto_altname": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_objectId_rand_explicit_id": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_objectId_rand_explicit_altname": { + "kms": "gcp", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_objectId_det_auto_id": { + "kms": "gcp", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_objectId_det_explicit_id": { + "kms": "gcp", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_objectId_det_explicit_altname": { + "kms": "gcp", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "gcp_bool_rand_auto_id": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": true + }, + "gcp_bool_rand_auto_altname": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": true + }, + "gcp_bool_rand_explicit_id": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": true + }, + "gcp_bool_rand_explicit_altname": { + "kms": "gcp", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": true + }, + "gcp_bool_det_explicit_id": { + "kms": "gcp", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "gcp_bool_det_explicit_altname": { + "kms": "gcp", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "gcp_date_rand_auto_id": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_date_rand_auto_altname": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_date_rand_explicit_id": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_date_rand_explicit_altname": { + "kms": "gcp", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_date_det_auto_id": { + "kms": "gcp", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_date_det_explicit_id": { + "kms": "gcp", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_date_det_explicit_altname": { + "kms": "gcp", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "gcp_null_rand_explicit_id": { + "kms": "gcp", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "gcp_null_rand_explicit_altname": { + "kms": "gcp", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "gcp_null_det_explicit_id": { + "kms": "gcp", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "gcp_null_det_explicit_altname": { + "kms": "gcp", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "gcp_regex_rand_auto_id": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_regex_rand_auto_altname": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_regex_rand_explicit_id": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_regex_rand_explicit_altname": { + "kms": "gcp", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_regex_det_auto_id": { + "kms": "gcp", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_regex_det_explicit_id": { + "kms": "gcp", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_regex_det_explicit_altname": { + "kms": "gcp", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "gcp_dbPointer_rand_auto_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_dbPointer_rand_auto_altname": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_dbPointer_rand_explicit_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_dbPointer_rand_explicit_altname": { + "kms": "gcp", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_dbPointer_det_auto_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_dbPointer_det_explicit_id": { + "kms": "gcp", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_dbPointer_det_explicit_altname": { + "kms": "gcp", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "gcp_javascript_rand_auto_id": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_javascript_rand_auto_altname": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_javascript_rand_explicit_id": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_javascript_rand_explicit_altname": { + "kms": "gcp", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_javascript_det_auto_id": { + "kms": "gcp", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_javascript_det_explicit_id": { + "kms": "gcp", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_javascript_det_explicit_altname": { + "kms": "gcp", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "gcp_symbol_rand_auto_id": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_symbol_rand_auto_altname": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_symbol_rand_explicit_id": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_symbol_rand_explicit_altname": { + "kms": "gcp", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_symbol_det_auto_id": { + "kms": "gcp", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_symbol_det_explicit_id": { + "kms": "gcp", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_symbol_det_explicit_altname": { + "kms": "gcp", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "gcp_javascriptWithScope_rand_auto_id": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_javascriptWithScope_rand_auto_altname": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_javascriptWithScope_rand_explicit_id": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_javascriptWithScope_rand_explicit_altname": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_javascriptWithScope_det_explicit_id": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_javascriptWithScope_det_explicit_altname": { + "kms": "gcp", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "gcp_int_rand_auto_id": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_int_rand_auto_altname": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_int_rand_explicit_id": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_int_rand_explicit_altname": { + "kms": "gcp", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_int_det_auto_id": { + "kms": "gcp", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_int_det_explicit_id": { + "kms": "gcp", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_int_det_explicit_altname": { + "kms": "gcp", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "gcp_timestamp_rand_auto_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_timestamp_rand_auto_altname": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_timestamp_rand_explicit_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_timestamp_rand_explicit_altname": { + "kms": "gcp", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_timestamp_det_auto_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_timestamp_det_explicit_id": { + "kms": "gcp", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_timestamp_det_explicit_altname": { + "kms": "gcp", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "gcp_long_rand_auto_id": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_long_rand_auto_altname": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_long_rand_explicit_id": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_long_rand_explicit_altname": { + "kms": "gcp", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_long_det_auto_id": { + "kms": "gcp", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_long_det_explicit_id": { + "kms": "gcp", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_long_det_explicit_altname": { + "kms": "gcp", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "gcp_decimal_rand_auto_id": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_decimal_rand_auto_altname": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_decimal_rand_explicit_id": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_decimal_rand_explicit_altname": { + "kms": "gcp", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_decimal_det_explicit_id": { + "kms": "gcp", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_decimal_det_explicit_altname": { + "kms": "gcp", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "gcp_minKey_rand_explicit_id": { + "kms": "gcp", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_minKey_rand_explicit_altname": { + "kms": "gcp", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_minKey_det_explicit_id": { + "kms": "gcp", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_minKey_det_explicit_altname": { + "kms": "gcp", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "gcp_maxKey_rand_explicit_id": { + "kms": "gcp", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_maxKey_rand_explicit_altname": { + "kms": "gcp", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_maxKey_det_explicit_id": { + "kms": "gcp", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "gcp_maxKey_det_explicit_altname": { + "kms": "gcp", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } }, "payload=0,algo=rand": { "kms": "local", @@ -2902,4 +6954,4 @@ "allowed": true, "value": "aaaaaaaaaaaaaaaa" } -} +} \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/external/external-key.json b/tests/SpecTests/client-side-encryption/external/external-key.json index 5da84ab6b..b3fe0723b 100644 --- a/tests/SpecTests/client-side-encryption/external/external-key.json +++ b/tests/SpecTests/client-side-encryption/external/external-key.json @@ -1,27 +1,27 @@ { "status": { "$numberInt": "1" - }, + }, "_id": { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } - }, + }, "masterKey": { "provider": "local" - }, + }, "updateDate": { "$date": { "$numberLong": "1557827033449" } - }, + }, "keyMaterial": { "$binary": { - "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", "subType": "00" } - }, + }, "creationDate": { "$date": { "$numberLong": "1557827033449" diff --git a/tests/SpecTests/client-side-encryption/external/external-schema.json b/tests/SpecTests/client-side-encryption/external/external-schema.json index 52f524a18..7d8cad8c3 100644 --- a/tests/SpecTests/client-side-encryption/external/external-schema.json +++ b/tests/SpecTests/client-side-encryption/external/external-schema.json @@ -5,12 +5,12 @@ "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } diff --git a/tests/SpecTests/client-side-encryption/limits/limits-doc.json b/tests/SpecTests/client-side-encryption/limits/limits-doc.json index 3c556aee0..53de52326 100644 --- a/tests/SpecTests/client-side-encryption/limits/limits-doc.json +++ b/tests/SpecTests/client-side-encryption/limits/limits-doc.json @@ -1,102 +1,102 @@ { - "00": "a", - "01": "a", - "02": "a", - "03": "a", - "04": "a", - "05": "a", - "06": "a", - "07": "a", - "08": "a", - "09": "a", - "10": "a", - "11": "a", - "12": "a", - "13": "a", - "14": "a", - "15": "a", - "16": "a", - "17": "a", - "18": "a", - "19": "a", - "20": "a", - "21": "a", - "22": "a", - "23": "a", - "24": "a", - "25": "a", - "26": "a", - "27": "a", - "28": "a", - "29": "a", - "30": "a", - "31": "a", - "32": "a", - "33": "a", - "34": "a", - "35": "a", - "36": "a", - "37": "a", - "38": "a", - "39": "a", - "40": "a", - "41": "a", - "42": "a", - "43": "a", - "44": "a", - "45": "a", - "46": "a", - "47": "a", - "48": "a", - "49": "a", - "50": "a", - "51": "a", - "52": "a", - "53": "a", - "54": "a", - "55": "a", - "56": "a", - "57": "a", - "58": "a", - "59": "a", - "60": "a", - "61": "a", - "62": "a", - "63": "a", - "64": "a", - "65": "a", - "66": "a", - "67": "a", - "68": "a", - "69": "a", - "70": "a", - "71": "a", - "72": "a", - "73": "a", - "74": "a", - "75": "a", - "76": "a", - "77": "a", - "78": "a", - "79": "a", - "80": "a", - "81": "a", - "82": "a", - "83": "a", - "84": "a", - "85": "a", - "86": "a", - "87": "a", - "88": "a", - "89": "a", - "90": "a", - "91": "a", - "92": "a", - "93": "a", - "94": "a", - "95": "a", - "96": "a", - "97": "a", - "98": "a", + "00": "a", + "01": "a", + "02": "a", + "03": "a", + "04": "a", + "05": "a", + "06": "a", + "07": "a", + "08": "a", + "09": "a", + "10": "a", + "11": "a", + "12": "a", + "13": "a", + "14": "a", + "15": "a", + "16": "a", + "17": "a", + "18": "a", + "19": "a", + "20": "a", + "21": "a", + "22": "a", + "23": "a", + "24": "a", + "25": "a", + "26": "a", + "27": "a", + "28": "a", + "29": "a", + "30": "a", + "31": "a", + "32": "a", + "33": "a", + "34": "a", + "35": "a", + "36": "a", + "37": "a", + "38": "a", + "39": "a", + "40": "a", + "41": "a", + "42": "a", + "43": "a", + "44": "a", + "45": "a", + "46": "a", + "47": "a", + "48": "a", + "49": "a", + "50": "a", + "51": "a", + "52": "a", + "53": "a", + "54": "a", + "55": "a", + "56": "a", + "57": "a", + "58": "a", + "59": "a", + "60": "a", + "61": "a", + "62": "a", + "63": "a", + "64": "a", + "65": "a", + "66": "a", + "67": "a", + "68": "a", + "69": "a", + "70": "a", + "71": "a", + "72": "a", + "73": "a", + "74": "a", + "75": "a", + "76": "a", + "77": "a", + "78": "a", + "79": "a", + "80": "a", + "81": "a", + "82": "a", + "83": "a", + "84": "a", + "85": "a", + "86": "a", + "87": "a", + "88": "a", + "89": "a", + "90": "a", + "91": "a", + "92": "a", + "93": "a", + "94": "a", + "95": "a", + "96": "a", + "97": "a", + "98": "a", "99": "a" } \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/limits/limits-key.json b/tests/SpecTests/client-side-encryption/limits/limits-key.json index 5da84ab6b..b3fe0723b 100644 --- a/tests/SpecTests/client-side-encryption/limits/limits-key.json +++ b/tests/SpecTests/client-side-encryption/limits/limits-key.json @@ -1,27 +1,27 @@ { "status": { "$numberInt": "1" - }, + }, "_id": { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } - }, + }, "masterKey": { "provider": "local" - }, + }, "updateDate": { "$date": { "$numberLong": "1557827033449" } - }, + }, "keyMaterial": { "$binary": { - "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", + "base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==", "subType": "00" } - }, + }, "creationDate": { "$date": { "$numberLong": "1557827033449" diff --git a/tests/SpecTests/client-side-encryption/limits/limits-schema.json b/tests/SpecTests/client-side-encryption/limits/limits-schema.json index 7af0979b8..c06908d9c 100644 --- a/tests/SpecTests/client-side-encryption/limits/limits-schema.json +++ b/tests/SpecTests/client-side-encryption/limits/limits-schema.json @@ -5,1401 +5,1401 @@ "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "01": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "02": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "03": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "04": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "05": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "06": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "07": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "08": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "09": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "10": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "11": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "12": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "13": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "14": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "15": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "16": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "17": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "18": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "19": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "20": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "21": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "22": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "23": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "24": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "25": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "26": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "27": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "28": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "29": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "30": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "31": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "32": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "33": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "34": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "35": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "36": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "37": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "38": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "39": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "40": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "41": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "42": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "43": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "44": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "45": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "46": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "47": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "48": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "49": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "50": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "51": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "52": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "53": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "54": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "55": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "56": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "57": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "58": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "59": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "60": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "61": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "62": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "63": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "64": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "65": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "66": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "67": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "68": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "69": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "70": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "71": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "72": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "73": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "74": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "75": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "76": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "77": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "78": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "79": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "80": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "81": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "82": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "83": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "84": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "85": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "86": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "87": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "88": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "89": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "90": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "91": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "92": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "93": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "94": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "95": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "96": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "97": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "98": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } - }, + }, "99": { "encrypt": { "keyId": [ { "$binary": { - "base64": "LOCALAAAAAAAAAAAAAAAAA==", + "base64": "LOCALAAAAAAAAAAAAAAAAA==", "subType": "04" } } - ], - "bsonType": "string", + ], + "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } } - }, + }, "bsonType": "object" } \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/tests/azureKMS.json b/tests/SpecTests/client-side-encryption/tests/azureKMS.json new file mode 100644 index 000000000..bf651f428 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/azureKMS.json @@ -0,0 +1,223 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_string_aws": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_azure": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZURE+AAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_gcp": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCP+AAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_local": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "AZURE+AAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "n+HWZ0ZSVOYA3cvQgP7inN4JSXfOH85IngmeQxRpQHjCCcqT3IFqEWNlrsVHiz3AELimHhX4HKqOLWMUeSIT6emUDDoQX9BAv8DR1+E1w4nGs/NyEneac78EYFkK3JysrFDOgl2ypCCTKAypkn9CkAx1if4cfgQE93LW4kczcyHdGiH36CIxrCDGv1UzAvERN5Qa47DVwsM6a+hWsF2AAAJVnF0wYLLJU07TuRHdMrrphPWXZsFgyV+lRqJ7DDpReKNO8nMPLV/mHqHBHGPGQiRdb9NoJo8CvokGz4+KE8oLwzKf6V24dtwZmRkrsDV4iOhvROAzz+Euo1ypSkL3mw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1601573901680" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1601573901680" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + }, + "keyAltNames": [ + "altname", + "azure_altname" + ] + } + ], + "tests": [ + { + "description": "Insert a document with auto encryption using Azure KMS provider", + "skipReason": "PHPLIB-619 RHEL platform is missing Azure root certificate", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "azure": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string_azure": "string0" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "datakeys" + }, + "$db": "keyvault" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AZURE+AAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string_azure": { + "$binary": { + "base64": "AQGVERPgAAAAAAAAAAAAAAAC5DbBSwPwfSlBrDtRuglvNvCXD1KzDuCKY2P+4bRFtHDjpTOE2XuytPAUaAbXf1orsPq59PVZmsbTZbt2CB8qaQ==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string_azure": { + "$binary": { + "base64": "AQGVERPgAAAAAAAAAAAAAAAC5DbBSwPwfSlBrDtRuglvNvCXD1KzDuCKY2P+4bRFtHDjpTOE2XuytPAUaAbXf1orsPq59PVZmsbTZbt2CB8qaQ==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/gcpKMS.json b/tests/SpecTests/client-side-encryption/tests/gcpKMS.json new file mode 100644 index 000000000..a715a7d15 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/gcpKMS.json @@ -0,0 +1,224 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_string_aws": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_azure": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZURE+AAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_gcp": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCP+AAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_local": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "GCP+AAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "CiQAIgLj0WyktnB4dfYHo5SLZ41K4ASQrjJUaSzl5vvVH0G12G0SiQEAjlV8XPlbnHDEDFbdTO4QIe8ER2/172U1ouLazG0ysDtFFIlSvWX5ZnZUrRMmp/R2aJkzLXEt/zf8Mn4Lfm+itnjgo5R9K4pmPNvvPKNZX5C16lrPT+aA+rd+zXFSmlMg3i5jnxvTdLHhg3G7Q/Uv1ZIJskKt95bzLoe0tUVzRWMYXLIEcohnQg==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1601574333107" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1601574333107" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + }, + "keyAltNames": [ + "altname", + "gcp_altname" + ] + } + ], + "tests": [ + { + "description": "Insert a document with auto encryption using GCP KMS provider", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "gcp": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string_gcp": "string0" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "datakeys" + }, + "$db": "keyvault" + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "GCP+AAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string_gcp": { + "$binary": { + "base64": "ARgj/gAAAAAAAAAAAAAAAAACwFd+Y5Ojw45GUXNvbcIpN9YkRdoHDHkR4kssdn0tIMKlDQOLFkWFY9X07IRlXsxPD8DcTiKnl6XINK28vhcGlg==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string_gcp": { + "$binary": { + "base64": "ARgj/gAAAAAAAAAAAAAAAAACwFd+Y5Ojw45GUXNvbcIpN9YkRdoHDHkR4kssdn0tIMKlDQOLFkWFY9X07IRlXsxPD8DcTiKnl6XINK28vhcGlg==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json b/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json index 144786290..c1088a0ec 100644 --- a/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json +++ b/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json @@ -50,6 +50,9 @@ "autoEncryptOpts": { "kmsProviders": { "aws": {} + }, + "extraOptions": { + "mongocryptdBypassSpawn": true } } }, From 903f190ad377231c31ce5705baf90a52d69ac960 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 19 Feb 2021 20:01:18 +0100 Subject: [PATCH 017/321] PHPLIB-617 Continuous Matrix Testing for 4.0 era drivers (#810) * Add scripts for matrix testing * Extract composer install to separate script * Move some version shenanigans to drivers-matrix-testing * Fix wrong exit in function * Rename matrix testing env variable * Simplify driver detection logic * Rename DRIVER_VERSION variable to remove conflicts with matrix testing vars * Update test info output * Remove xtrace option in scripts * Set PHP patch version automatically * Use groups to skip tests for matrix testing --- .evergreen/config/php.ini | 1 + .evergreen/install-dependencies.sh | 132 ++++++++++++++++++ .evergreen/run-tests.sh | 59 ++++++++ phpunit.evergreen.xml | 32 +++++ tests/Collection/CollectionFunctionalTest.php | 4 + tests/Collection/CrudSpecFunctionalTest.php | 2 + tests/Database/DatabaseFunctionalTest.php | 5 + tests/DocumentationExamplesTest.php | 1 + tests/FunctionalTestCase.php | 9 ++ tests/Model/IndexInfoFunctionalTest.php | 1 + tests/Operation/AggregateFunctionalTest.php | 20 ++- .../ListCollectionsFunctionalTest.php | 4 + tests/Operation/MapReduceFunctionalTest.php | 4 + .../ModifyCollectionFunctionalTest.php | 5 + tests/Operation/WatchFunctionalTest.php | 30 ++++ 15 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 .evergreen/config/php.ini create mode 100755 .evergreen/install-dependencies.sh create mode 100755 .evergreen/run-tests.sh create mode 100644 phpunit.evergreen.xml diff --git a/.evergreen/config/php.ini b/.evergreen/config/php.ini new file mode 100644 index 000000000..45969d065 --- /dev/null +++ b/.evergreen/config/php.ini @@ -0,0 +1 @@ +extension=mongodb.so diff --git a/.evergreen/install-dependencies.sh b/.evergreen/install-dependencies.sh new file mode 100755 index 000000000..16892dbd5 --- /dev/null +++ b/.evergreen/install-dependencies.sh @@ -0,0 +1,132 @@ +#!/bin/sh +set -o errexit # Exit the script with error if any of the commands fail + +set_php_version () +{ + PHP_VERSION=$1 + + if [ ! -d "/opt/php" ]; then + echo "PHP is not available" + exit 1 + fi + + if [ -d "/opt/php/${PHP_VERSION}-64bit/bin" ]; then + export PHP_PATH="/opt/php/${PHP_VERSION}-64bit/bin" + else + # Try to find the newest version matching our constant + export PHP_PATH=`find /opt/php/ -maxdepth 1 -type d -name "${PHP_VERSION}.*-64bit" -print | sort -V -r | head -1` + fi + + if [ ! -d "$PHP_PATH" ]; then + echo "Could not find PHP binaries for version ${PHP_VERSION}. Listing available versions..." + ls -1 /opt/php + exit 1 + fi + + export PATH=$PHP_PATH/bin:$PATH +} + +install_extension () +{ + # Workaround to get PECL running on PHP 7.0 +# export PHP_PEAR_PHP_BIN=${PHP_PATH}/bin/php +# export PHP_PEAR_INSTALL_DIR=${PHP_PATH}/bin/php + + rm -f ${PHP_PATH}/lib/php.ini + + if [ "x${EXTENSION_BRANCH}" != "x" ] || [ "x${EXTENSION_REPO}" != "x" ]; then + CLONE_REPO=${EXTENSION_REPO:-https://github.com/mongodb/mongo-php-driver} + CHECKOUT_BRANCH=${EXTENSION_BRANCH:-master} + + echo "Compiling driver branch ${CHECKOUT_BRANCH} from repository ${CLONE_REPO}" + + mkdir -p /tmp/compile + rm -rf /tmp/compile/mongo-php-driver + git clone ${CLONE_REPO} /tmp/compile/mongo-php-driver + cd /tmp/compile/mongo-php-driver + + git checkout ${CHECKOUT_BRANCH} + git submodule update --init + phpize + ./configure --enable-mongodb-developer-flags + make all -j20 > /dev/null + make install + + cd ${PROJECT_DIRECTORY} + elif [ "x${EXTENSION_VERSION}" != "x" ]; then + echo "Installing driver version ${EXTENSION_VERSION} from PECL" + pecl install -f mongodb-${EXTENSION_VERSION} + else + echo "Installing latest driver version from PECL" + pecl install -f mongodb + fi + + sudo cp ${PROJECT_DIRECTORY}/.evergreen/config/php.ini ${PHP_PATH}/lib/php.ini + + php --ri mongodb +} + +install_composer () +{ + EXPECTED_CHECKSUM="$(php -r 'copy("https://composer.github.io/installer.sig", "php://stdout");')" + php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" + ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" + + if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ]; then + >&2 echo 'ERROR: Invalid installer checksum' + rm composer-setup.php + exit 1 + fi + + php composer-setup.php --quiet + rm composer-setup.php +} + +# Functions to fetch MongoDB binaries +. ${DRIVERS_TOOLS}/.evergreen/download-mongodb.sh +OS=$(uname -s | tr '[:upper:]' '[:lower:]') + +get_distro + +case "$DISTRO" in + cygwin*) + echo "Install Windows dependencies" + ;; + + darwin*) + echo "Install macOS dependencies" + ;; + + linux-rhel*) + echo "Install RHEL dependencies" + ;; + + linux-ubuntu*) + echo "Install Ubuntu dependencies" + sudo apt-get install -y awscli || true + ;; + + sunos*) + echo "Install Solaris dependencies" + sudo /opt/csw/bin/pkgutil -y -i sasl_dev || true + ;; + + *) + echo "All other platforms..." + ;; +esac + +case "$DEPENDENCIES" in + lowest*) + COMPOSER_FLAGS="${COMPOSER_FLAGS} --prefer-lowest" + ;; + + *) + ;; +esac + +set_php_version $PHP_VERSION +install_extension +install_composer + +php composer.phar update $COMPOSER_FLAGS diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh new file mode 100755 index 000000000..1cb956996 --- /dev/null +++ b/.evergreen/run-tests.sh @@ -0,0 +1,59 @@ +#!/bin/sh +set -o errexit # Exit the script with error if any of the commands fail + +# Supported/used environment variables: +# AUTH Set to enable authentication. Defaults to "noauth" +# SSL Set to enable SSL. Defaults to "nossl" +# MONGODB_URI Set the suggested connection MONGODB_URI (including credentials and topology info) +# MARCH Machine Architecture. Defaults to lowercase uname -m + + +AUTH=${AUTH:-noauth} +SSL=${SSL:-nossl} +MONGODB_URI=${MONGODB_URI:-} +TESTS=${TESTS:-} +IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-false} + +# For matrix testing, we have to determine the correct driver version +if [ "$IS_MATRIX_TESTING" == "true" ]; then + case "${DRIVER_MONGODB_VERSION}" in + '4.4') + export EXTENSION_VERSION='1.8.2' + ;; + '4.2') + export EXTENSION_VERSION='1.6.1' + ;; + '4.0') + export EXTENSION_VERSION='1.5.5' + ;; + esac + + case "${MONGODB_VERSION}" in + latest) + MONGODB_VERSION_NUMBER='5.0' + ;; + *) + MONGODB_VERSION_NUMBER=$MONGODB_VERSION + ;; + esac + + PHPUNIT_OPTS="--dont-report-useless-tests --exclude-group matrix-testing-server-${MONGODB_VERSION_NUMBER}-driver-${DRIVER_MONGODB_VERSION},matrix-testing-server-${MONGODB_VERSION_NUMBER}-driver-${DRIVER_MONGODB_VERSION}-topology-${TOPOLOGY}" + + DIR=$(dirname $0) + . $DIR/install-dependencies.sh +fi + +OS=$(uname -s | tr '[:upper:]' '[:lower:]') +[ -z "$MARCH" ] && MARCH=$(uname -m | tr '[:upper:]' '[:lower:]') + +echo "Running tests with $AUTH and $SSL, connecting to: $MONGODB_URI" + +# Disable failing PHPUnit due to deprecations +export SYMFONY_DEPRECATIONS_HELPER=999999 + +# Run the tests, and store the results in a Evergreen compatible JSON results file +case "$TESTS" in + *) + php vendor/bin/phpunit --configuration phpunit.evergreen.xml $PHPUNIT_OPTS + ;; +esac diff --git a/phpunit.evergreen.xml b/phpunit.evergreen.xml new file mode 100644 index 000000000..cfd1a1b4d --- /dev/null +++ b/phpunit.evergreen.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + ./tests/ + + + + + + + diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 7132ab006..8c09086c4 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -227,6 +227,10 @@ public function testWithOptionsPassesOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } + /** + * @group matrix-testing-server-4.4-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.0 + */ public function testMapReduce() { $this->createFixtures(3); diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index 73ae22ab4..80acabeda 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -12,6 +12,8 @@ * CRUD spec functional tests. * * @see https://github.com/mongodb/specifications/tree/master/source/crud/tests + * + * @group matrix-testing-server-5.0-driver-4.0 */ class CrudSpecFunctionalTest extends FunctionalTestCase { diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 6e51c7cb9..5cb4f8e77 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -153,6 +153,11 @@ public function testGetSelectsCollectionAndInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-sharded_cluster + * @group matrix-testing-server-4.4-driver-4.0-topology-sharded_cluster + * @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster + */ public function testModifyCollection() { $this->database->createCollection($this->getCollectionName()); diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 1dd63d8e2..f3bc6281d 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -919,6 +919,7 @@ public function testExample_55_58() $this->assertInventoryCount(0); } + /** @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster */ public function testChangeStreamExample_1_4() { if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) { diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 2c3bc01e7..95138379a 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -48,6 +48,10 @@ protected function assertSameObjectId($expectedObjectId, $actualObjectId) protected function getFeatureCompatibilityVersion(ReadPreference $readPreference = null) { + if ($this->isShardedCluster()) { + return $this->getServerVersion($readPreference); + } + if (version_compare($this->getServerVersion(), '3.4.0', '<')) { return $this->getServerVersion($readPreference); } @@ -133,4 +137,9 @@ protected function skipIfTransactionsAreNotSupported() $this->markTestSkipped('Transactions require WiredTiger storage engine'); } } + + protected function isShardedCluster() + { + return $this->getPrimaryServer()->getType() == Server::TYPE_MONGOS; + } } diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index c02617e81..93845c8b2 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -42,6 +42,7 @@ public function testIs2dSphere() $this->assertEquals($expectedVersion, $index['2dsphereIndexVersion']); } + /** @group matrix-testing-server-5.0-driver-4.0 */ public function testIsGeoHaystack() { $indexName = $this->collection->createIndex(['pos' => 'geoHaystack', 'x' => 1], ['bucketSize' => 5]); diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php index f11be7c7a..a3cf5b453 100644 --- a/tests/Operation/AggregateFunctionalTest.php +++ b/tests/Operation/AggregateFunctionalTest.php @@ -162,7 +162,13 @@ public function testExplainOption() $results = iterator_to_array($operation->execute($this->getPrimaryServer())); $this->assertCount(1, $results); - $this->assertArrayHasKey('stages', $results[0]); + + /* MongoDB 4.2 may optimize aggregate pipelines into queries, which can + * result in different explain output (see: SERVER-24860) */ + $this->assertThat($results[0], $this->logicalOr( + $this->arrayHasKey('stages'), + $this->arrayHasKey('queryPlanner') + )); } public function testExplainOptionWithWriteConcern() @@ -183,7 +189,17 @@ function() use ($pipeline, $options) { $results = iterator_to_array($operation->execute($this->getPrimaryServer())); $this->assertCount(1, $results); - $this->assertObjectHasAttribute('stages', current($results)); + $result = current($results); + + /* MongoDB 4.2 may optimize aggregate pipelines into queries, which can + * result in different explain output (see: SERVER-24860) */ + if (isset($result->shards)) { + foreach ($result->shards as $shard) { + $this->assertObjectHasAttribute('stages', $shard); + } + } else { + $this->assertObjectHasAttribute('stages', $result); + } }, function(array $event) { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); diff --git a/tests/Operation/ListCollectionsFunctionalTest.php b/tests/Operation/ListCollectionsFunctionalTest.php index 3f93e650d..c44065e75 100644 --- a/tests/Operation/ListCollectionsFunctionalTest.php +++ b/tests/Operation/ListCollectionsFunctionalTest.php @@ -34,6 +34,10 @@ public function testListCollectionsForNewlyCreatedDatabase() } } + /** + * @group matrix-testing-server-4.4-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.0 + */ public function testIdIndexAndInfo() { if (version_compare($this->getServerVersion(), '3.4.0', '<')) { diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index bc70c705f..36db4eb05 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -11,6 +11,10 @@ use MongoDB\Tests\CommandObserver; use stdClass; +/** + * @group matrix-testing-server-4.4-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.0 + */ class MapReduceFunctionalTest extends FunctionalTestCase { public function testDefaultReadConcernIsOmitted() diff --git a/tests/Operation/ModifyCollectionFunctionalTest.php b/tests/Operation/ModifyCollectionFunctionalTest.php index 1bbdb4bdf..139ff3fbf 100644 --- a/tests/Operation/ModifyCollectionFunctionalTest.php +++ b/tests/Operation/ModifyCollectionFunctionalTest.php @@ -8,6 +8,11 @@ class ModifyCollectionFunctionalTest extends FunctionalTestCase { + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-sharded_cluster + * @group matrix-testing-server-4.4-driver-4.0-topology-sharded_cluster + * @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster + */ public function testCollMod() { $operation = new CreateCollection($this->getDatabaseName(), $this->getCollectionName()); diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index 61532f9d3..b26d68e72 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -19,6 +19,11 @@ use stdClass; use ReflectionClass; +/** + * @group matrix-testing-server-4.2-driver-4.0-topology-sharded_cluster + * @group matrix-testing-server-4.4-driver-4.0-topology-sharded_cluster + * @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster + */ class WatchFunctionalTest extends FunctionalTestCase { private static $wireVersionForStartAtOperationTime = 7; @@ -590,6 +595,11 @@ public function testInitialCursorIsNotClosed() $this->assertFalse($cursor->isDead()); } + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + */ public function testNextResumeTokenNotFound() { $pipeline = [['$project' => ['_id' => 0 ]]]; @@ -606,6 +616,11 @@ public function testNextResumeTokenNotFound() $changeStream->next(); } + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + */ public function testRewindResumeTokenNotFound() { $pipeline = [['$project' => ['_id' => 0 ]]]; @@ -620,6 +635,11 @@ public function testRewindResumeTokenNotFound() $changeStream->rewind(); } + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + */ public function testNextResumeTokenInvalidType() { $pipeline = [['$project' => ['_id' => ['$literal' => 'foo']]]]; @@ -636,6 +656,11 @@ public function testNextResumeTokenInvalidType() $changeStream->next(); } + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + */ public function testRewindResumeTokenInvalidType() { $pipeline = [['$project' => ['_id' => ['$literal' => 'foo']]]]; @@ -822,6 +847,11 @@ public function testNextAdvancesKey() $this->assertSame(1, $changeStream->key()); } + /** + * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + */ public function testResumeTokenNotFoundAdvancesKey() { $pipeline = [['$project' => ['_id' => 0 ]]]; From 7f889f434f02932c2bd5df54cdbbca8bf790eb6f Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 4 Mar 2021 13:44:53 +0100 Subject: [PATCH 018/321] PHPLIB-616 Continuous Matrix Testing for 4.2 era drivers (#812) * Skip failing tests for 4.2 driver * Don't attempt to drop admin database in spec tests --- tests/Collection/CollectionFunctionalTest.php | 2 ++ tests/Model/IndexInfoFunctionalTest.php | 5 ++++- tests/Operation/ListCollectionsFunctionalTest.php | 2 ++ tests/Operation/MapReduceFunctionalTest.php | 2 ++ tests/SpecTests/FunctionalTestCase.php | 4 ++++ tests/SpecTests/RetryableReadsSpecTest.php | 3 +++ 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 2a1d3f5aa..934d5f920 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -381,7 +381,9 @@ public function testWithOptionsPassesOptions() /** * @group matrix-testing-server-4.4-driver-4.0 + * @group matrix-testing-server-4.4-driver-4.2 * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.2 */ public function testMapReduce() { diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index 7f1794a1f..d6da335cb 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -47,7 +47,10 @@ public function testIs2dSphere() $this->assertEquals($expectedVersion, $index['2dsphereIndexVersion']); } - /** @group matrix-testing-server-5.0-driver-4.0 */ + /** + * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.2 + */ public function testIsGeoHaystack() { $indexName = $this->collection->createIndex(['pos' => 'geoHaystack', 'x' => 1], ['bucketSize' => 5]); diff --git a/tests/Operation/ListCollectionsFunctionalTest.php b/tests/Operation/ListCollectionsFunctionalTest.php index f3dbb5a1e..6cdfda5ef 100644 --- a/tests/Operation/ListCollectionsFunctionalTest.php +++ b/tests/Operation/ListCollectionsFunctionalTest.php @@ -38,7 +38,9 @@ public function testListCollectionsForNewlyCreatedDatabase() /** * @group matrix-testing-server-4.4-driver-4.0 + * @group matrix-testing-server-4.4-driver-4.2 * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.2 */ public function testIdIndexAndInfo() { diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index 77cded247..424ab868c 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -14,7 +14,9 @@ /** * @group matrix-testing-server-4.4-driver-4.0 + * @group matrix-testing-server-4.4-driver-4.2 * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-server-5.0-driver-4.2 */ class MapReduceFunctionalTest extends FunctionalTestCase { diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index b7e276aa8..6e23061aa 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -186,6 +186,10 @@ protected function dropTestAndOutcomeCollections() { $context = $this->getContext(); + if ($context->databaseName === 'admin') { + return; + } + if ($context->bucketName !== null) { $bucket = $context->getGridFSBucket($context->defaultWriteOptions); $bucket->drop(); diff --git a/tests/SpecTests/RetryableReadsSpecTest.php b/tests/SpecTests/RetryableReadsSpecTest.php index 414ae46cd..d79e779b8 100644 --- a/tests/SpecTests/RetryableReadsSpecTest.php +++ b/tests/SpecTests/RetryableReadsSpecTest.php @@ -42,6 +42,9 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * Execute an individual test case from the specification. * * @dataProvider provideTests + * @group matrix-testing-server-4.4-driver-4.2 + * @group matrix-testing-server-5.0-driver-4.2 + * * @param stdClass $test Individual "tests[]" document * @param array $runOn Top-level "runOn" array with server requirements * @param array|object $data Top-level "data" array to initialize collection From 2e2e205ff4c6f78b5cd4584faffe3674cd53e615 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 4 Mar 2021 13:46:52 +0100 Subject: [PATCH 019/321] Rename matrix testing exclusion groups --- .evergreen/run-tests.sh | 2 +- tests/Collection/CollectionFunctionalTest.php | 4 +- tests/Collection/CrudSpecFunctionalTest.php | 2 +- tests/Database/DatabaseFunctionalTest.php | 6 +-- tests/DocumentationExamplesTest.php | 48 +++++++++---------- tests/Model/IndexInfoFunctionalTest.php | 2 +- .../ListCollectionsFunctionalTest.php | 4 +- tests/Operation/MapReduceFunctionalTest.php | 4 +- .../ModifyCollectionFunctionalTest.php | 6 +-- tests/Operation/WatchFunctionalTest.php | 36 +++++++------- 10 files changed, 57 insertions(+), 57 deletions(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 1cb956996..258ebfc29 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -37,7 +37,7 @@ if [ "$IS_MATRIX_TESTING" == "true" ]; then ;; esac - PHPUNIT_OPTS="--dont-report-useless-tests --exclude-group matrix-testing-server-${MONGODB_VERSION_NUMBER}-driver-${DRIVER_MONGODB_VERSION},matrix-testing-server-${MONGODB_VERSION_NUMBER}-driver-${DRIVER_MONGODB_VERSION}-topology-${TOPOLOGY}" + PHPUNIT_OPTS="--dont-report-useless-tests --exclude-group matrix-testing-exclude-server-${MONGODB_VERSION_NUMBER}-driver-${DRIVER_MONGODB_VERSION},matrix-testing-exclude-server-${MONGODB_VERSION_NUMBER}-driver-${DRIVER_MONGODB_VERSION}-topology-${TOPOLOGY}" DIR=$(dirname $0) . $DIR/install-dependencies.sh diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 8c09086c4..9eb49b61f 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -228,8 +228,8 @@ public function testWithOptionsPassesOptions() } /** - * @group matrix-testing-server-4.4-driver-4.0 - * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-exclude-server-4.4-driver-4.0 + * @group matrix-testing-exclude-server-5.0-driver-4.0 */ public function testMapReduce() { diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index 80acabeda..b010ae1cc 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -13,7 +13,7 @@ * * @see https://github.com/mongodb/specifications/tree/master/source/crud/tests * - * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-exclude-server-5.0-driver-4.0 */ class CrudSpecFunctionalTest extends FunctionalTestCase { diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 5cb4f8e77..4ce18a9cf 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -154,9 +154,9 @@ public function testGetSelectsCollectionAndInheritsOptions() } /** - * @group matrix-testing-server-4.2-driver-4.0-topology-sharded_cluster - * @group matrix-testing-server-4.4-driver-4.0-topology-sharded_cluster - * @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ public function testModifyCollection() { diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index f3bc6281d..da13024b6 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -63,19 +63,19 @@ public function testExample_3() // Start Example 3 $insertManyResult = $db->inventory->insertMany([ [ - 'item' => 'journal', + 'item' => 'journal', 'qty' => 25, 'tags' => ['blank', 'red'], 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], ], [ - 'item' => 'mat', + 'item' => 'mat', 'qty' => 85, 'tags' => ['gray'], 'size' => ['h' => 27.9, 'w' => 35.5, 'uom' => 'cm'], ], [ - 'item' => 'mousepad', + 'item' => 'mousepad', 'qty' => 25, 'tags' => ['gel', 'blue'], 'size' => ['h' => 19, 'w' => 22.85, 'uom' => 'cm'], @@ -97,31 +97,31 @@ public function testExample_6_13() // Start Example 6 $insertManyResult = $db->inventory->insertMany([ [ - 'item' => 'journal', + 'item' => 'journal', 'qty' => 25, 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], 'status' => 'A', ], [ - 'item' => 'notebook', + 'item' => 'notebook', 'qty' => 50, 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], 'status' => 'A', ], [ - 'item' => 'paper', + 'item' => 'paper', 'qty' => 100, 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], 'status' => 'D', ], [ - 'item' => 'planner', + 'item' => 'planner', 'qty' => 75, 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], 'status' => 'D', ], [ - 'item' => 'postcard', + 'item' => 'postcard', 'qty' => 45, 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], 'status' => 'A', @@ -200,31 +200,31 @@ public function testExample_14_19() // Start Example 14 $insertManyResult = $db->inventory->insertMany([ [ - 'item' => 'journal', + 'item' => 'journal', 'qty' => 25, 'size' => ['h' => 14, 'w' => 21, 'uom' => 'cm'], 'status' => 'A', ], [ - 'item' => 'notebook', + 'item' => 'notebook', 'qty' => 50, 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], 'status' => 'A', ], [ - 'item' => 'paper', + 'item' => 'paper', 'qty' => 100, 'size' => ['h' => 8.5, 'w' => 11, 'uom' => 'in'], 'status' => 'D', ], [ - 'item' => 'planner', + 'item' => 'planner', 'qty' => 75, 'size' => ['h' => 22.85, 'w' => 30, 'uom' => 'cm'], 'status' => 'D', ], [ - 'item' => 'postcard', + 'item' => 'postcard', 'qty' => 45, 'size' => ['h' => 10, 'w' => 15.25, 'uom' => 'cm'], 'status' => 'A', @@ -280,31 +280,31 @@ public function testExample_20_28() // Start Example 20 $insertManyResult = $db->inventory->insertMany([ [ - 'item' => 'journal', + 'item' => 'journal', 'qty' => 25, 'tags' => ['blank', 'red'], 'dim_cm' => [14, 21], ], [ - 'item' => 'notebook', + 'item' => 'notebook', 'qty' => 50, 'tags' => ['red', 'blank'], 'dim_cm' => [14, 21], ], [ - 'item' => 'paper', + 'item' => 'paper', 'qty' => 100, 'tags' => ['red', 'blank', 'plain'], 'dim_cm' => [14, 21], ], [ - 'item' => 'planner', + 'item' => 'planner', 'qty' => 75, 'tags' => ['blank', 'red'], 'dim_cm' => [22.85, 30], ], [ - 'item' => 'postcard', + 'item' => 'postcard', 'qty' => 45, 'tags' => ['blue'], 'dim_cm' => [10, 15.25], @@ -386,34 +386,34 @@ public function testExample_29_37() // Start Example 29 $insertManyResult = $db->inventory->insertMany([ [ - 'item' => 'journal', + 'item' => 'journal', 'instock' => [ ['warehouse' => 'A', 'qty' => 5], ['warehouse' => 'C', 'qty' => 15], ], ], [ - 'item' => 'notebook', + 'item' => 'notebook', 'instock' => [ ['warehouse' => 'C', 'qty' => 5], ], ], [ - 'item' => 'paper', + 'item' => 'paper', 'instock' => [ ['warehouse' => 'A', 'qty' => 60], ['warehouse' => 'B', 'qty' => 15], ], ], [ - 'item' => 'planner', + 'item' => 'planner', 'instock' => [ ['warehouse' => 'A', 'qty' => 40], ['warehouse' => 'B', 'qty' => 5], ], ], [ - 'item' => 'postcard', + 'item' => 'postcard', 'instock' => [ ['warehouse' => 'B', 'qty' => 15], ['warehouse' => 'C', 'qty' => 35], @@ -919,7 +919,7 @@ public function testExample_55_58() $this->assertInventoryCount(0); } - /** @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster */ + /** @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ public function testChangeStreamExample_1_4() { if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) { diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index 93845c8b2..25a3163ec 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -42,7 +42,7 @@ public function testIs2dSphere() $this->assertEquals($expectedVersion, $index['2dsphereIndexVersion']); } - /** @group matrix-testing-server-5.0-driver-4.0 */ + /** @group matrix-testing-exclude-server-5.0-driver-4.0 */ public function testIsGeoHaystack() { $indexName = $this->collection->createIndex(['pos' => 'geoHaystack', 'x' => 1], ['bucketSize' => 5]); diff --git a/tests/Operation/ListCollectionsFunctionalTest.php b/tests/Operation/ListCollectionsFunctionalTest.php index c44065e75..5deb71330 100644 --- a/tests/Operation/ListCollectionsFunctionalTest.php +++ b/tests/Operation/ListCollectionsFunctionalTest.php @@ -35,8 +35,8 @@ public function testListCollectionsForNewlyCreatedDatabase() } /** - * @group matrix-testing-server-4.4-driver-4.0 - * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-exclude-server-4.4-driver-4.0 + * @group matrix-testing-exclude-server-5.0-driver-4.0 */ public function testIdIndexAndInfo() { diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index 36db4eb05..2ffc5da5e 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -12,8 +12,8 @@ use stdClass; /** - * @group matrix-testing-server-4.4-driver-4.0 - * @group matrix-testing-server-5.0-driver-4.0 + * @group matrix-testing-exclude-server-4.4-driver-4.0 + * @group matrix-testing-exclude-server-5.0-driver-4.0 */ class MapReduceFunctionalTest extends FunctionalTestCase { diff --git a/tests/Operation/ModifyCollectionFunctionalTest.php b/tests/Operation/ModifyCollectionFunctionalTest.php index 139ff3fbf..d11a0af9b 100644 --- a/tests/Operation/ModifyCollectionFunctionalTest.php +++ b/tests/Operation/ModifyCollectionFunctionalTest.php @@ -9,9 +9,9 @@ class ModifyCollectionFunctionalTest extends FunctionalTestCase { /** - * @group matrix-testing-server-4.2-driver-4.0-topology-sharded_cluster - * @group matrix-testing-server-4.4-driver-4.0-topology-sharded_cluster - * @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ public function testCollMod() { diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index b26d68e72..219b8c0d1 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -20,9 +20,9 @@ use ReflectionClass; /** - * @group matrix-testing-server-4.2-driver-4.0-topology-sharded_cluster - * @group matrix-testing-server-4.4-driver-4.0-topology-sharded_cluster - * @group matrix-testing-server-5.0-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-sharded_cluster + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ class WatchFunctionalTest extends FunctionalTestCase { @@ -596,9 +596,9 @@ public function testInitialCursorIsNotClosed() } /** - * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set - * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set - * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-replica_set */ public function testNextResumeTokenNotFound() { @@ -617,9 +617,9 @@ public function testNextResumeTokenNotFound() } /** - * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set - * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set - * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-replica_set */ public function testRewindResumeTokenNotFound() { @@ -636,9 +636,9 @@ public function testRewindResumeTokenNotFound() } /** - * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set - * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set - * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-replica_set */ public function testNextResumeTokenInvalidType() { @@ -657,9 +657,9 @@ public function testNextResumeTokenInvalidType() } /** - * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set - * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set - * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-replica_set */ public function testRewindResumeTokenInvalidType() { @@ -848,9 +848,9 @@ public function testNextAdvancesKey() } /** - * @group matrix-testing-server-4.2-driver-4.0-topology-replica_set - * @group matrix-testing-server-4.4-driver-4.0-topology-replica_set - * @group matrix-testing-server-5.0-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-replica_set + * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-replica_set */ public function testResumeTokenNotFoundAdvancesKey() { From 1ba1892d28ed62a11dd1581fd7ac50ce38837305 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 5 Mar 2021 13:44:32 +0100 Subject: [PATCH 020/321] PHPLIB-615 Matrix testing for 4.4 era drivers (#813) * Skip geoHaystack test for 4.4 driver * Use majority write concern when updating key vaults * Use early exit in insertKeyVaultData --- tests/Model/IndexInfoFunctionalTest.php | 1 + .../ClientSideEncryptionSpecTest.php | 46 +++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index 5f2113195..591e8fc17 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -50,6 +50,7 @@ public function testIs2dSphere() /** * @group matrix-testing-exclude-server-5.0-driver-4.0 * @group matrix-testing-exclude-server-5.0-driver-4.2 + * @group matrix-testing-exclude-server-5.0-driver-4.4 */ public function testIsGeoHaystack() { diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index e0311a729..b37c137fd 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -168,9 +168,12 @@ public function provideTests() */ public function testDataKeyAndDoubleEncryption(Closure $test) { - $client = new Client(static::getUri()); + $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); + $client = $this->getContext()->getClient(); - $client->selectCollection('keyvault', 'datakeys')->drop(); + // This empty call ensures that the key vault is dropped with a majority + // write concern + $this->insertKeyVaultData([]); $client->selectCollection('db', 'coll')->drop(); $encryptionOpts = [ @@ -312,13 +315,17 @@ function ($command) use (&$commands) { */ public function testExternalKeyVault($withExternalKeyVault) { - $client = new Client(static::getUri()); - - $client->selectCollection('keyvault', 'datakeys')->drop(); + $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); + $client = $this->getContext()->getClient(); $client->selectCollection('db', 'coll')->drop(); - $keyId = $client - ->selectCollection('keyvault', 'datakeys') + $keyVaultCollection = $client->selectCollection( + 'keyvault', + 'datakeys', + ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $this->getContext()->defaultWriteOptions + ); + $keyVaultCollection->drop(); + $keyId = $keyVaultCollection ->insertOne($this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-key.json'))) ->getInsertedId(); @@ -370,13 +377,15 @@ public function testExternalKeyVault($withExternalKeyVault) */ public function testBSONSizeLimitsAndBatchSplitting() { - $client = new Client(static::getUri()); + $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); + $client = $this->getContext()->getClient(); - $client->selectCollection('keyvault', 'datakeys')->drop(); $client->selectCollection('db', 'coll')->drop(); - $client->selectDatabase('db')->createCollection('coll', ['validator' => ['$jsonSchema' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-schema.json'))]]); - $client->selectCollection('keyvault', 'datakeys')->insertOne($this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-key.json'))); + + $this->insertKeyVaultData([ + $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-key.json')), + ]); $autoEncryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', @@ -491,7 +500,8 @@ public function testViewsAreProhibited() */ public function testCorpus($schemaMap = true) { - $client = new Client(static::getUri()); + $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); + $client = $this->getContext()->getClient(); $client->selectDatabase('db')->dropCollection('coll'); @@ -503,8 +513,7 @@ public function testCorpus($schemaMap = true) ->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); } - $client->selectDatabase('keyvault')->dropCollection('datakeys'); - $client->selectCollection('keyvault', 'datakeys')->insertMany([ + $this->insertKeyVaultData([ $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-local.json')), $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-aws.json')), ]); @@ -738,16 +747,15 @@ private function encryptCorpusValue(stdClass $data, ClientEncryption $clientEncr private function insertKeyVaultData(array $keyVaultData = null) { + $context = $this->getContext(); + $collection = $context->selectCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $context->defaultWriteOptions); + $collection->drop(); + if (empty($keyVaultData)) { return; } - $context = $this->getContext(); - $collection = $context->selectCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $context->defaultWriteOptions); - $collection->drop(); $collection->insertMany($keyVaultData); - - return; } private function prepareCorpusData(stdClass $data, ClientEncryption $clientEncryption) From 02021065c17439e0ce851ac89b199900e9126680 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 5 Mar 2021 15:05:27 +0100 Subject: [PATCH 021/321] Fix test failures due to wrong merge --- .evergreen/run-tests.sh | 2 +- .../ClientSideEncryptionSpecTest.php | 28 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index d9aa5bb24..20e9fcc20 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -12,7 +12,7 @@ AUTH=${AUTH:-noauth} SSL=${SSL:-nossl} MONGODB_URI=${MONGODB_URI:-} TESTS=${TESTS:-} -IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-false} +IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} # For matrix testing, we have to determine the correct driver version if [ "$IS_MATRIX_TESTING" == "true" ]; then diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index e643e998a..d02f56587 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -320,12 +320,14 @@ public function testExternalKeyVault($withExternalKeyVault) $client = $this->getContext()->getClient(); $client->selectCollection('db', 'coll')->drop(); - $keyId = $client - ->selectCollection('keyvault', 'datakeys') - ->insertOne( - $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-key.json')), - ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] - ) + $keyVaultCollection = $client->selectCollection( + 'keyvault', + 'datakeys', + ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $this->getContext()->defaultWriteOptions + ); + $keyVaultCollection->drop(); + $keyId = $keyVaultCollection + ->insertOne($this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-key.json'))) ->getInsertedId(); $encryptionOpts = [ @@ -400,14 +402,15 @@ function () use ($collection) { ]); }, function ($command) use (&$commands) { + if ($command['started']->getCommandName() !== 'insert') { + return; + } + $commands[] = $command; } ); $test->assertCount(2, $commands); - foreach ($commands as $command) { - $test->assertSame('insert', $command['started']->getCommandName()); - } }, ]; @@ -428,14 +431,15 @@ function () use ($collection, $document) { ]); }, function ($command) use (&$commands) { + if ($command['started']->getCommandName() !== 'insert') { + return; + } + $commands[] = $command; } ); $test->assertCount(2, $commands); - foreach ($commands as $command) { - $test->assertSame('insert', $command['started']->getCommandName()); - } }, ]; From 52c5c98aa5d8f98cacfd1b8a047dd594968869a2 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 9 Mar 2021 14:53:17 +0100 Subject: [PATCH 022/321] Fix atlas data lake tests --- .evergreen/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index ccb0b30df..fcc4700be 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -224,6 +224,7 @@ functions: working_dir: "src" script: | ${PREPARE_SHELL} + export PATH="${PHP_PATH}/bin:$PATH" PHP_VERSION=${PHP_VERSION} TESTS="atlas-data-lake" AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "cleanup": @@ -603,7 +604,7 @@ buildvariants: - name: "test-sharded_cluster" - matrix_name: "atlas-data-lake-test" - matrix_spec: { "php-edge-versions": "latest-stable" } + matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest" } display_name: "Atlas Data Lake test" run_on: rhel70 tasks: From 3ace4fad66692049c0880ab9de9a853e543b903b Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 25 Mar 2021 08:28:11 +0100 Subject: [PATCH 023/321] PHPLIB-624 Sync change stream spec tests for delta oplog entries (#814) --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 ++ .../change-streams/change-streams.json | 116 ++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams.json diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index c33f1d52e..8a2631282 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -178,6 +178,19 @@ public function provideFailingTests() return $this->provideTests(__DIR__ . '/valid-fail'); } + /** + * @dataProvider provideChangeStreamsTests + */ + public function testChangeStreams(...$args) + { + $this->doTestCase(...$args); + } + + public function provideChangeStreamsTests() + { + return $this->provideTests(__DIR__ . '/change-streams'); + } + private function provideTests(string $dir) { $testArgs = []; diff --git a/tests/UnifiedSpecTests/change-streams/change-streams.json b/tests/UnifiedSpecTests/change-streams/change-streams.json new file mode 100644 index 000000000..adaf00de2 --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams.json @@ -0,0 +1,116 @@ +{ + "description": "change-streams", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [] + } + ], + "tests": [ + { + "description": "Test array truncation", + "runOnRequirements": [ + { + "minServerVersion": "4.7", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1, + "array": [ + "foo", + { + "a": "bar" + }, + 1, + 2, + 3 + ] + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "array": [ + "foo", + { + "a": "bar" + } + ] + } + } + ] + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "updateDescription": { + "updatedFields": {}, + "removedFields": [], + "truncatedArrays": [ + { + "field": "array", + "newSize": 2 + } + ] + } + } + } + ] + } + ] +} From 2c80b35dbb0a4ccb2b1f0a678b81a3059271bfeb Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 25 Mar 2021 09:05:49 +0100 Subject: [PATCH 024/321] PHPLIB-618: Change estimatedDocumentCount to use $collStats (#811) * PHPLIB-618: Change estimatedDocumentCount to use $collStats * Address CR * Fix checkstyle errors --- src/Operation/EstimatedDocumentCount.php | 83 +- tests/FunctionalTestCase.php | 3 +- .../ClientSideEncryptionSpecTest.php | 8 +- .../estimatedDocumentCount-4.9.json | 246 +++++ ...son => estimatedDocumentCount-pre4.9.json} | 2 + ...timatedDocumentCount-serverErrors-4.9.json | 911 ++++++++++++++++++ ...tedDocumentCount-serverErrors-pre4.9.json} | 2 + tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 + .../crud/estimatedDocumentCount.json | 562 +++++++++++ 9 files changed, 1814 insertions(+), 16 deletions(-) create mode 100644 tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json rename tests/SpecTests/retryable-reads/{estimatedDocumentCount.json => estimatedDocumentCount-pre4.9.json} (97%) create mode 100644 tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json rename tests/SpecTests/retryable-reads/{estimatedDocumentCount-serverErrors.json => estimatedDocumentCount-serverErrors-pre4.9.json} (99%) create mode 100644 tests/UnifiedSpecTests/crud/estimatedDocumentCount.json diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index 2e6dd5ca1..dd9bcb4bf 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -17,12 +17,18 @@ namespace MongoDB\Operation; +use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; +use MongoDB\Driver\ReadConcern; +use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; +use MongoDB\Driver\Session; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; use function array_intersect_key; +use function is_integer; +use function MongoDB\server_supports_feature; /** * Operation for obtaining an estimated count of documents in a collection @@ -42,11 +48,15 @@ class EstimatedDocumentCount implements Executable, Explainable /** @var array */ private $options; - /** @var Count */ - private $count; + /** @var int */ + private static $errorCodeCollectionNotFound = 26; + + /** @var int */ + private static $wireVersionForCollStats = 12; /** - * Constructs a count command. + * Constructs a command to get the estimated number of documents in a + * collection. * * Supported options: * @@ -73,9 +83,24 @@ public function __construct($databaseName, $collectionName, array $options = []) { $this->databaseName = (string) $databaseName; $this->collectionName = (string) $collectionName; - $this->options = array_intersect_key($options, ['maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); - $this->count = $this->createCount(); + if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { + throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); + } + + if (isset($options['readConcern']) && ! $options['readConcern'] instanceof ReadConcern) { + throw InvalidArgumentException::invalidType('"readConcern" option', $options['readConcern'], ReadConcern::class); + } + + if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { + throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class); + } + + if (isset($options['session']) && ! $options['session'] instanceof Session) { + throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); + } + + $this->options = array_intersect_key($options, ['maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); } /** @@ -90,18 +115,54 @@ public function __construct($databaseName, $collectionName, array $options = []) */ public function execute(Server $server) { - return $this->count->execute($server); + $command = $this->createCommand($server); + + if ($command instanceof Aggregate) { + try { + $cursor = $command->execute($server); + } catch (CommandException $e) { + if ($e->getCode() == self::$errorCodeCollectionNotFound) { + return 0; + } + + throw $e; + } + + $cursor->rewind(); + + return $cursor->current()->n; + } + + return $command->execute($server); } public function getCommandDocument(Server $server) { - return $this->count->getCommandDocument($server); + return $this->createCommand($server)->getCommandDocument($server); } - /** - * @return Count - */ - private function createCount() + private function createAggregate() : Aggregate + { + return new Aggregate( + $this->databaseName, + $this->collectionName, + [ + ['$collStats' => ['count' => (object) []]], + ['$group' => ['_id' => 1, 'n' => ['$sum' => '$count']]], + ], + $this->options + ); + } + + /** @return Aggregate|Count */ + private function createCommand(Server $server) + { + return server_supports_feature($server, self::$wireVersionForCollStats) + ? $this->createAggregate() + : $this->createCount(); + } + + private function createCount() : Count { return new Count($this->databaseName, $this->collectionName, [], $this->options); } diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index aaaba5f42..e75c4e2a2 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -32,6 +32,7 @@ use function phpinfo; use function preg_match; use function preg_quote; +use function preg_replace; use function sprintf; use function version_compare; use const INFO_MODULES; @@ -278,7 +279,7 @@ protected function getServerVersion(ReadPreference $readPreference = null) $document = current($cursor->toArray()); if (isset($document['version']) && is_string($document['version'])) { - return $document['version']; + return preg_replace('#^(\d+\.\d+\.\d+).*$#', '\1', $document['version']); } throw new UnexpectedValueException('Could not determine server version'); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 4816496b2..5528436a5 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -395,8 +395,8 @@ function ($command) use (&$commands) { } ); - $test->assertCount(2, $commands); - }, + $test->assertCount(2, $commands); + }, ]; yield 'Test 4' => [ @@ -424,8 +424,8 @@ function ($command) use (&$commands) { } ); - $test->assertCount(2, $commands); - }, + $test->assertCount(2, $commands); + }, ]; yield 'Test 5' => [ diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json new file mode 100644 index 000000000..7925bd5ef --- /dev/null +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json @@ -0,0 +1,246 @@ +{ + "runOn": [ + { + "minServerVersion": "4.9.0" + } + ], + "database_name": "retryable-reads-tests", + "collection_name": "coll", + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "EstimatedDocumentCount succeeds on first attempt", + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds on second attempt", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails on first attempt", + "clientOptions": { + "retryReads": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails on second attempt", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-pre4.9.json similarity index 97% rename from tests/SpecTests/retryable-reads/estimatedDocumentCount.json rename to tests/SpecTests/retryable-reads/estimatedDocumentCount-pre4.9.json index 8dfa15a2c..44be966ae 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-pre4.9.json @@ -2,6 +2,7 @@ "runOn": [ { "minServerVersion": "4.0", + "maxServerVersion": "4.8.99", "topology": [ "single", "replicaset" @@ -9,6 +10,7 @@ }, { "minServerVersion": "4.1.7", + "maxServerVersion": "4.8.99", "topology": [ "sharded" ] diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json new file mode 100644 index 000000000..1e1adfb92 --- /dev/null +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json @@ -0,0 +1,911 @@ +{ + "runOn": [ + { + "minServerVersion": "4.9.0" + } + ], + "database_name": "retryable-reads-tests", + "collection_name": "coll", + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "EstimatedDocumentCount succeeds after InterruptedAtShutdown", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 11600 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after InterruptedDueToReplStateChange", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 11602 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NotMaster", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 10107 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NotMasterNoSlaveOk", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 13435 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NotMasterOrSecondary", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 13436 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after PrimarySteppedDown", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 189 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after ShutdownInProgress", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 91 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after HostNotFound", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 7 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after HostUnreachable", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 6 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NetworkTimeout", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 89 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after SocketException", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 9001 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails after two NotMaster errors", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 10107 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails after NotMaster when retryReads is false", + "clientOptions": { + "retryReads": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 10107 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json similarity index 99% rename from tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors.json rename to tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json index 1af21d1fe..c11e609cd 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json @@ -2,6 +2,7 @@ "runOn": [ { "minServerVersion": "4.0", + "maxServerVersion": "4.8.99", "topology": [ "single", "replicaset" @@ -9,6 +10,7 @@ }, { "minServerVersion": "4.1.7", + "maxServerVersion": "4.8.99", "topology": [ "sharded" ] diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 8a2631282..ad944ee9f 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -141,6 +141,19 @@ private function doTestCase(stdClass $test, string $schemaVersion, array $runOnR } } + /** + * @dataProvider provideCrudTests + */ + public function testCrud(...$args) + { + $this->doTestCase(...$args); + } + + public function provideCrudTests() + { + return $this->provideTests(__DIR__ . '/crud'); + } + /** * @dataProvider providePassingTests */ diff --git a/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json b/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json new file mode 100644 index 000000000..9dc084589 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json @@ -0,0 +1,562 @@ +{ + "description": "estimatedDocumentCount", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "uriOptions": { + "retryReads": false + }, + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "edc-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "edc-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "estimatedDocumentCount uses $collStats on 4.9.0 or greater", + "runOnRequirements": [ + { + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount with maxTimeMS on 4.9.0 or greater", + "runOnRequirements": [ + { + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "maxTimeMS": 6000 + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ], + "maxTimeMS": 6000 + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount on non-existent collection on 4.9.0 or greater", + "runOnRequirements": [ + { + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection1", + "expectResult": 0 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll1", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--command error", + "runOnRequirements": [ + { + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 8 + } + } + } + }, + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "errorCode": 8 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--socket error", + "runOnRequirements": [ + { + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + } + } + }, + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount uses count on less than 4.9.0", + "runOnRequirements": [ + { + "maxServerVersion": "4.8.99" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0" + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount with maxTimeMS on less than 4.9.0", + "runOnRequirements": [ + { + "maxServerVersion": "4.8.99" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "maxTimeMS": 6000 + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0", + "maxTimeMS": 6000 + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount on non-existent collection on less than 4.9.0", + "runOnRequirements": [ + { + "maxServerVersion": "4.8.99" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection1", + "expectResult": 0 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll1" + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on less than 4.9.0--command error", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "count" + ], + "errorCode": 8 + } + } + } + }, + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "errorCode": 8 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0" + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on less than 4.9.0--socket error", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "count" + ], + "closeConnection": true + } + } + } + }, + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0" + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + } + ] +} From d1b18dd51dad81eea60ab7b71a7bcc0c0190845e Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 30 Mar 2021 11:25:58 +0200 Subject: [PATCH 025/321] PHPLIB-622 Versioned MongoDB API for Drivers (#816) * Support new serverParameters runOnRequirement in unified test runner * Sync unified-test-format tests * Run versioned API spec tests This syncs the versioned API spec tests to commit a49cbdf605176a7035c0343779170ce412cc3f0e * Add helper to create client and manager objects * Add build variant to test with requireApiVersion=true * Address code review feedback * Don't export API_VERSION env variable --- .evergreen/config.yml | 22 +- .evergreen/run-tests.sh | 1 + tests/ClientFunctionalTest.php | 2 +- tests/DocumentationExamplesTest.php | 7 +- tests/FunctionalTestCase.php | 26 +- .../Operation/FindAndModifyFunctionalTest.php | 3 +- tests/Operation/WatchFunctionalTest.php | 3 +- tests/SpecTests/AtlasDataLakeSpecTest.php | 9 +- .../ClientSideEncryptionSpecTest.php | 23 +- tests/SpecTests/Context.php | 18 +- tests/SpecTests/CrudSpecTest.php | 3 +- tests/SpecTests/PrimaryStepDownSpecTest.php | 2 +- tests/SpecTests/TransactionsSpecTest.php | 8 +- tests/UnifiedSpecTests/Context.php | 20 +- tests/UnifiedSpecTests/RunOnRequirement.php | 19 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 52 +- .../entity-client-apiVersion-unsupported.json | 20 + .../valid-pass/poc-change-streams.json | 6 +- .../valid-pass/poc-gridfs.json | 4 +- .../valid-pass/poc-retryable-writes.json | 14 +- .../crud-api-version-1-strict.json | 1115 +++++++++++++++++ .../versioned-api/crud-api-version-1.json | 1106 ++++++++++++++++ ...ommand-helper-no-api-version-declared.json | 117 ++ .../test-commands-deprecation-errors.json | 74 ++ .../test-commands-strict-mode.json | 74 ++ .../versioned-api/transaction-handling.json | 519 ++++++++ 26 files changed, 3203 insertions(+), 64 deletions(-) create mode 100644 tests/UnifiedSpecTests/valid-fail/entity-client-apiVersion-unsupported.json create mode 100644 tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json create mode 100644 tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json create mode 100644 tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json create mode 100644 tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json create mode 100644 tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json create mode 100644 tests/UnifiedSpecTests/versioned-api/transaction-handling.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index fcc4700be..2cbec2ea6 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -176,7 +176,7 @@ functions: params: script: | ${PREPARE_SHELL} - MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: @@ -215,7 +215,7 @@ functions: export GCP_EMAIL="${client_side_encryption_gcp_email}" export GCP_PRIVATEKEY="${client_side_encryption_gcp_privatekey}" export PATH="${PHP_PATH}/bin:$PATH" - PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run atlas data lake test": - command: shell.exec @@ -357,6 +357,17 @@ tasks: - func: "bootstrap mongohoused" - func: "run atlas data lake test" + - name: "test-requireApiVersion" + tags: ["versioned_api"] + commands: + - func: "bootstrap mongo-orchestration" + vars: + TOPOLOGY: "server" + AUTH: "auth" + REQUIRE_API_VERSION: "yes" + - func: "run tests" + vars: + API_VERSION: "1" # }}} @@ -609,3 +620,10 @@ buildvariants: run_on: rhel70 tasks: - name: "test-atlas-data-lake" + +- matrix_name: "test-requireApiVersion" + matrix_spec: { "php-edge-versions": "latest-stable", "versions": "latest", "driver-versions": "latest" } + display_name: "Versioned API - ${versions}" + run_on: rhel70 + tasks: + - name: "test-requireApiVersion" diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 53cdbe016..8842c8ca9 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -12,6 +12,7 @@ AUTH=${AUTH:-noauth} SSL=${SSL:-nossl} MONGODB_URI=${MONGODB_URI:-} TESTS=${TESTS:-} +API_VERSION=${API_VERSION:-} IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} # For matrix testing, we have to determine the correct driver version diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index 59d71cea9..ef07ab679 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -28,7 +28,7 @@ private function doSetUp() { parent::setUp(); - $this->client = new Client(static::getUri()); + $this->client = static::createTestClient(); $this->client->dropDatabase($this->getDatabaseName()); } diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index f0da3614b..c3a68492c 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -4,7 +4,6 @@ use MongoDB\BSON\ObjectId; use MongoDB\BSON\UTCDateTime; -use MongoDB\Client; use MongoDB\Database; use MongoDB\Driver\Cursor; use MongoDB\Driver\Exception\Exception; @@ -1270,7 +1269,7 @@ public function testTransactions_intro_example_1() $this->assertNotNull('This test intentionally performs no assertions'); - $client = new Client(static::getUri()); + $client = static::createTestClient(); /* The WC is required: https://docs.mongodb.com/manual/core/transactions/#transactions-and-locks */ $client->hr->dropCollection('employees', ['writeConcern' => new WriteConcern('majority')]); @@ -1445,7 +1444,7 @@ public function testTransactions_retry_example_3() $this->assertNotNull('This test intentionally performs no assertions'); - $client = new Client(static::getUri()); + $client = static::createTestClient(); /* The WC is required: https://docs.mongodb.com/manual/core/transactions/#transactions-and-locks */ $client->hr->dropCollection('employees', ['writeConcern' => new WriteConcern('majority')]); @@ -1470,7 +1469,7 @@ public function testCausalConsistency() $this->assertNotNull('This test intentionally performs no assertions'); // Prep - $client = new Client(static::getUri()); + $client = static::createTestClient(); $items = $client->selectDatabase( 'test', [ 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY) ] diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index e75c4e2a2..cfcdfee0f 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -4,12 +4,14 @@ use InvalidArgumentException; use MongoDB\BSON\ObjectId; +use MongoDB\Client; use MongoDB\Driver\Command; use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Manager; use MongoDB\Driver\Query; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; +use MongoDB\Driver\ServerApi; use MongoDB\Driver\WriteConcern; use MongoDB\Operation\CreateCollection; use MongoDB\Operation\DatabaseCommand; @@ -21,6 +23,7 @@ use function count; use function current; use function explode; +use function getenv; use function implode; use function is_array; use function is_object; @@ -51,7 +54,7 @@ private function doSetUp() { parent::setUp(); - $this->manager = new Manager(static::getUri()); + $this->manager = static::createTestManager(); $this->configuredFailPoints = []; } @@ -62,6 +65,16 @@ private function doTearDown() parent::tearDown(); } + public static function createTestClient(string $uri = null, array $options = [], array $driverOptions = []) : Client + { + return new Client($uri ?? static::getUri(), $options, static::appendServerApiOption($driverOptions)); + } + + public static function createTestManager(string $uri = null, array $options = [], array $driverOptions = []) : Manager + { + return new Manager($uri ?? static::getUri(), $options, static::appendServerApiOption($driverOptions)); + } + public static function getUri($allowMultipleMongoses = false) { $uri = parent::getUri(); @@ -86,7 +99,7 @@ public static function getUri($allowMultipleMongoses = false) return $uri; } - $manager = new Manager($uri); + $manager = static::createTestManager($uri); if ($manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY))->getType() !== Server::TYPE_MONGOS) { return $uri; } @@ -428,6 +441,15 @@ protected function skipIfTransactionsAreNotSupported() } } + private static function appendServerApiOption(array $driverOptions) : array + { + if (getenv('API_VERSION') && ! isset($driverOptions['serverApi'])) { + $driverOptions['serverApi'] = new ServerApi(getenv('API_VERSION')); + } + + return $driverOptions; + } + /** * Disables any fail points that were configured earlier in the test. * diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index d402f4717..10539797b 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -3,7 +3,6 @@ namespace MongoDB\Tests\Operation; use MongoDB\Driver\BulkWrite; -use MongoDB\Driver\Manager; use MongoDB\Driver\ReadPreference; use MongoDB\Model\BSONDocument; use MongoDB\Operation\FindAndModify; @@ -17,7 +16,7 @@ class FindAndModifyFunctionalTest extends FunctionalTestCase */ public function testManagerReadConcernIsOmitted() { - $manager = new Manager(static::getUri(), ['readConcernLevel' => 'majority']); + $manager = static::createTestManager(null, ['readConcernLevel' => 'majority']); $server = $manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); (new CommandObserver())->observe( diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index f749e2c27..426aec4af 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -11,7 +11,6 @@ use MongoDB\Driver\Exception\ConnectionTimeoutException; use MongoDB\Driver\Exception\LogicException; use MongoDB\Driver\Exception\ServerException; -use MongoDB\Driver\Manager; use MongoDB\Driver\Monitoring\CommandSucceededEvent; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; @@ -166,7 +165,7 @@ public function testNextResumesAfterConnectionException() /* In order to trigger a dropped connection, we'll use a new client with * a socket timeout that is less than the change stream's maxAwaitTimeMS * option. */ - $manager = new Manager(static::getUri(), ['socketTimeoutMS' => 50]); + $manager = static::createTestManager(null, ['socketTimeoutMS' => 50]); $primaryServer = $manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); $operation = new Watch($manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); diff --git a/tests/SpecTests/AtlasDataLakeSpecTest.php b/tests/SpecTests/AtlasDataLakeSpecTest.php index 1e4fda722..96e992f18 100644 --- a/tests/SpecTests/AtlasDataLakeSpecTest.php +++ b/tests/SpecTests/AtlasDataLakeSpecTest.php @@ -2,7 +2,6 @@ namespace MongoDB\Tests\SpecTests; -use MongoDB\Client; use MongoDB\Driver\Command; use MongoDB\Driver\Cursor; use MongoDB\Tests\CommandObserver; @@ -135,7 +134,7 @@ public function testKillCursors() (new CommandObserver())->observe( function () { - $client = new Client(static::getUri()); + $client = static::createTestClient(); $client->test->driverdata->find([], ['batchSize' => 2, 'limit' => 3]); }, function (array $event) use (&$cursorId, &$cursorNamespace) { @@ -205,7 +204,7 @@ public function testConnectWithoutAuth() $uri = $parts['scheme'] . '://' . $parts['host'] . $port . $path . $query; - $client = new Client($uri); + $client = static::createTestClient($uri); $cursor = $client->selectDatabase($this->getDatabaseName())->command(['ping' => 1]); $this->assertInstanceOf(Cursor::class, $cursor); @@ -217,7 +216,7 @@ public function testConnectWithoutAuth() */ public function testConnectwithSCRAMSHA1() { - $client = new Client(static::getUri(), ['authMechanism' => 'SCRAM-SHA-1']); + $client = static::createTestClient(null, ['authMechanism' => 'SCRAM-SHA-1']); $cursor = $client->selectDatabase($this->getDatabaseName())->command(['ping' => 1]); $this->assertInstanceOf(Cursor::class, $cursor); @@ -229,7 +228,7 @@ public function testConnectwithSCRAMSHA1() */ public function testConnectwithSCRAMSHA256() { - $client = new Client(static::getUri(), ['authMechanism' => 'SCRAM-SHA-256']); + $client = static::createTestClient(null, ['authMechanism' => 'SCRAM-SHA-256']); $cursor = $client->selectDatabase($this->getDatabaseName())->command(['ping' => 1]); $this->assertInstanceOf(Cursor::class, $cursor); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 5528436a5..43b627240 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -5,7 +5,6 @@ use Closure; use MongoDB\BSON\Binary; use MongoDB\BSON\Int64; -use MongoDB\Client; use MongoDB\Collection; use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Exception\AuthenticationException; @@ -206,7 +205,7 @@ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey) 'keyVaultClient' => $client, ]; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncryption = $clientEncrypted->createClientEncryption($encryptionOpts); $commands = []; @@ -323,7 +322,7 @@ public function testExternalKeyVault($withExternalKeyVault) ]; if ($withExternalKeyVault) { - $encryptionOpts['keyVaultClient'] = new Client(static::getUri(), ['username' => 'fake-user', 'password' => 'fake-pwd']); + $encryptionOpts['keyVaultClient'] = static::createTestClient(null, ['username' => 'fake-user', 'password' => 'fake-pwd']); } $autoEncryptionOpts = $encryptionOpts + [ @@ -332,7 +331,7 @@ public function testExternalKeyVault($withExternalKeyVault) ], ]; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncryption = $clientEncrypted->createClientEncryption($encryptionOpts); try { @@ -469,7 +468,7 @@ public function testBSONSizeLimitsAndBatchSplitting(Closure $test) 'keyVaultClient' => $client, ]; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $collection = $clientEncrypted->selectCollection('db', 'coll'); @@ -483,7 +482,7 @@ public function testBSONSizeLimitsAndBatchSplitting(Closure $test) */ public function testViewsAreProhibited() { - $client = new Client(static::getUri()); + $client = static::createTestClient(); $client->selectCollection('db', 'view')->drop(); $client->selectDatabase('db')->command(['create' => 'view', 'viewOn' => 'coll']); @@ -495,7 +494,7 @@ public function testViewsAreProhibited() ], ]; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); try { $clientEncrypted->selectCollection('db', 'view')->insertOne(['foo' => 'bar']); @@ -557,7 +556,7 @@ public function testCorpus($schemaMap = true) $corpus = (array) $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus.json')); $corpusCopied = []; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncryption = $clientEncrypted->createClientEncryption($encryptionOpts); $collection = $clientEncrypted->selectCollection('db', 'coll'); @@ -621,7 +620,7 @@ public function testCorpus($schemaMap = true) */ public function testCustomEndpoint(Closure $test) { - $client = new Client(static::getUri()); + $client = static::createTestClient(); $clientEncryption = $client->createClientEncryption([ 'keyVaultNamespace' => 'keyvault.datakeys', @@ -758,7 +757,7 @@ public function testBypassSpawningMongocryptdViaBypassSpawn() ], ]; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); try { $clientEncrypted->selectCollection('db', 'coll')->insertOne(['encrypted' => 'test']); @@ -787,11 +786,11 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption() ], ]; - $clientEncrypted = new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]); + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncrypted->selectCollection('db', 'coll')->insertOne(['encrypted' => 'test']); - $clientMongocryptd = new Client('mongodb://localhost:27021'); + $clientMongocryptd = static::createTestClient('mongodb://localhost:27021'); $this->expectException(ConnectionTimeoutException::class); $clientMongocryptd->selectDatabase('db')->command(['isMaster' => true]); diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 1d0e6bd8c..4c9e16a8a 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -93,7 +93,7 @@ public static function fromChangeStreams(stdClass $test, $databaseName, $collect { $o = new self($databaseName, $collectionName); - $o->client = new Client(FunctionalTestCase::getUri()); + $o->client = FunctionalTestCase::createTestClient(); return $o; } @@ -132,10 +132,10 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ $o->outcomeCollectionName = $test->outcome->collection->name; } - $o->client = new Client(FunctionalTestCase::getUri(), $clientOptions, $driverOptions); + $o->client = FunctionalTestCase::createTestClient(null, $clientOptions, $driverOptions); if ($autoEncryptionOptions !== []) { - $o->encryptedClient = new Client(FunctionalTestCase::getUri(), $clientOptions, $driverOptions + ['autoEncryption' => $autoEncryptionOptions]); + $o->encryptedClient = FunctionalTestCase::createTestClient(null, $clientOptions, $driverOptions + ['autoEncryption' => $autoEncryptionOptions]); } return $o; @@ -145,7 +145,7 @@ public static function fromCommandMonitoring(stdClass $test, $databaseName, $col { $o = new self($databaseName, $collectionName); - $o->client = new Client(FunctionalTestCase::getUri()); + $o->client = FunctionalTestCase::createTestClient(); return $o; } @@ -169,7 +169,7 @@ public static function fromCrud(stdClass $test, $databaseName, $collectionName) 'readPreference' => new ReadPreference('primary'), ]; - $o->client = new Client(FunctionalTestCase::getUri(), $clientOptions); + $o->client = FunctionalTestCase::createTestClient(null, $clientOptions); return $o; } @@ -184,7 +184,7 @@ public static function fromReadWriteConcern(stdClass $test, $databaseName, $coll $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - $o->client = new Client(FunctionalTestCase::getUri(), $clientOptions); + $o->client = FunctionalTestCase::createTestClient(null, $clientOptions); return $o; } @@ -197,7 +197,7 @@ public static function fromRetryableReads(stdClass $test, $databaseName, $collec $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - $o->client = new Client(FunctionalTestCase::getUri(), $clientOptions); + $o->client = FunctionalTestCase::createTestClient(null, $clientOptions); return $o; } @@ -212,7 +212,7 @@ public static function fromRetryableWrites(stdClass $test, $databaseName, $colle $o->outcomeCollectionName = $test->outcome->collection->name; } - $o->client = new Client(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); + $o->client = FunctionalTestCase::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); return $o; } @@ -237,7 +237,7 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti * re-using a previously persisted libmongoc client object. */ $clientOptions += ['p' => mt_rand()]; - $o->client = new Client(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); + $o->client = FunctionalTestCase::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); $session0Options = isset($test->sessionOptions->session0) ? (array) $test->sessionOptions->session0 : []; $session1Options = isset($test->sessionOptions->session1) ? (array) $test->sessionOptions->session1 : []; diff --git a/tests/SpecTests/CrudSpecTest.php b/tests/SpecTests/CrudSpecTest.php index 8835b92e6..c7f38ead3 100644 --- a/tests/SpecTests/CrudSpecTest.php +++ b/tests/SpecTests/CrudSpecTest.php @@ -2,7 +2,6 @@ namespace MongoDB\Tests\SpecTests; -use MongoDB\Client; use MongoDB\Driver\Exception\BulkWriteException; use stdClass; use function basename; @@ -144,7 +143,7 @@ public function testErrInfoIsPropagated() ], ]); - $client = new Client(static::getUri()); + $client = FunctionalTestCase::createTestClient(); try { $client->selectCollection($this->getDatabaseName(), $this->getCollectionName())->insertOne(['fail' => 1]); diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php index 53c215e6c..c496444aa 100644 --- a/tests/SpecTests/PrimaryStepDownSpecTest.php +++ b/tests/SpecTests/PrimaryStepDownSpecTest.php @@ -38,7 +38,7 @@ private function doSetUp() { parent::setUp(); - $this->client = new Client(static::getUri(), ['retryWrites' => false, 'heartbeatFrequencyMS' => 500, 'serverSelectionTimeoutMS' => 20000, 'serverSelectionTryOnce' => false]); + $this->client = self::createTestClient(null, ['retryWrites' => false, 'heartbeatFrequencyMS' => 500, 'serverSelectionTimeoutMS' => 20000, 'serverSelectionTryOnce' => false]); $this->dropAndRecreateCollection(); $this->collection = $this->client->selectCollection($this->getDatabaseName(), $this->getCollectionName()); diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 2bec5ab41..0f8136215 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -4,10 +4,8 @@ use MongoDB\BSON\Int64; use MongoDB\BSON\Timestamp; -use MongoDB\Client; use MongoDB\Driver\Command; use MongoDB\Driver\Exception\ServerException; -use MongoDB\Driver\Manager; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use stdClass; @@ -209,7 +207,7 @@ public function testStartingNewTransactionOnPinnedSessionUnpinsSession() $this->markTestSkipped('Mongos pinning tests can only run on sharded clusters using replica sets'); } - $client = new Client($this->getUri(true)); + $client = self::createTestClient($this->getUri(true)); $session = $client->startSession(); $collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName()); @@ -247,7 +245,7 @@ public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession() $this->markTestSkipped('Mongos pinning tests can only run on sharded clusters using replica sets'); } - $client = new Client($this->getUri(true)); + $client = self::createTestClient($this->getUri(true)); $session = $client->startSession(); $collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName()); @@ -292,7 +290,7 @@ protected function createTestCollection() */ private static function killAllSessions() { - $manager = new Manager(static::getUri()); + $manager = static::createTestManager(); $primary = $manager->selectServer(new ReadPreference('primary')); $servers = $primary->getType() === Server::TYPE_MONGOS diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index b62a5a733..5971688b2 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -4,9 +4,9 @@ use LogicException; use MongoDB\Client; -use MongoDB\Driver\Manager; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; +use MongoDB\Driver\ServerApi; use stdClass; use function array_key_exists; use function array_map; @@ -208,11 +208,12 @@ static function (string $tag) : array { private function createClient(string $id, stdClass $o) { - Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents']); + Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents', 'serverApi']); $useMultipleMongoses = $o->useMultipleMongoses ?? null; $observeEvents = $o->observeEvents ?? null; $ignoreCommandMonitoringEvents = $o->ignoreCommandMonitoringEvents ?? []; + $serverApi = $o->serverApi ?? null; $uri = $this->uri; @@ -256,7 +257,16 @@ private function createClient(string $id, stdClass $o) static $i = 0; $driverOptions = isset($observeEvents) ? ['i' => $i++] : []; - $this->entityMap->set($id, new Client($uri, $uriOptions, $driverOptions)); + if ($serverApi !== null) { + assertIsObject($serverApi); + $driverOptions['serverApi'] = new ServerApi( + $serverApi->version, + $serverApi->strict ?? null, + $serverApi->deprecationErrors ?? null + ); + } + + $this->entityMap->set($id, UnifiedSpecTest::createTestClient($uri, $uriOptions, $driverOptions)); } private function createCollection(string $id, stdClass $o) @@ -400,7 +410,7 @@ private static function removeMultipleMongoses(string $uri) : string { assertStringStartsWith('mongodb://', $uri); - $manager = new Manager($uri); + $manager = UnifiedSpecTest::createTestManager($uri); // Nothing to do if the URI does not refer to a sharded cluster if ($manager->selectServer(new ReadPreference(ReadPreference::PRIMARY))->getType() !== Server::TYPE_MONGOS) { @@ -440,7 +450,7 @@ private static function requireMultipleMongoses(string $uri) { assertStringStartsWith('mongodb://', $uri); - $manager = new Manager($uri); + $manager = UnifiedSpecTest::createTestManager($uri); // Nothing to do if the URI does not refer to a sharded cluster if ($manager->selectServer(new ReadPreference(ReadPreference::PRIMARY))->getType() !== Server::TYPE_MONGOS) { diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index 909d3c1ab..0c372e03d 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -2,10 +2,12 @@ namespace MongoDB\Tests\UnifiedSpecTests; +use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use stdClass; use function in_array; use function PHPUnit\Framework\assertContainsOnly; use function PHPUnit\Framework\assertIsArray; +use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertMatchesRegularExpression; use function version_compare; @@ -28,6 +30,9 @@ class RunOnRequirement /** @var array */ private $topologies; + /** @var stdClass */ + private $serverParameters; + public function __construct(stdClass $o) { if (isset($o->minServerVersion)) { @@ -47,9 +52,14 @@ public function __construct(stdClass $o) assertContainsOnly('string', $o->topologies); $this->topologies = $o->topologies; } + + if (isset($o->serverParameters)) { + assertIsObject($o->serverParameters); + $this->serverParameters = $o->serverParameters; + } } - public function isSatisfied(string $serverVersion, string $topology) : bool + public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters) : bool { if (isset($this->minServerVersion) && version_compare($serverVersion, $this->minServerVersion, '<')) { return false; @@ -73,6 +83,13 @@ public function isSatisfied(string $serverVersion, string $topology) : bool return false; } + if (isset($this->serverParameters)) { + $constraint = new Matches($this->serverParameters, null, true, false); + if (! $constraint->evaluate($serverParameters, '', true)) { + return false; + } + } + return true; } } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index ad944ee9f..a20dffdc9 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -3,8 +3,8 @@ namespace MongoDB\Tests\UnifiedSpecTests; use Exception; -use MongoDB\Client; use MongoDB\Collection; +use MongoDB\Driver\Command; use MongoDB\Driver\Exception\ServerException; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; @@ -33,7 +33,7 @@ class UnifiedSpecTest extends FunctionalTestCase const SERVER_ERROR_INTERRUPTED = 11601; const MIN_SCHEMA_VERSION = '1.0'; - const MAX_SCHEMA_VERSION = '1.1'; + const MAX_SCHEMA_VERSION = '1.2'; const TOPOLOGY_SINGLE = 'single'; const TOPOLOGY_REPLICASET = 'replicaset'; @@ -52,7 +52,7 @@ private static function doSetUpBeforeClass() /* Provide internal client unmodified URI, since it may need to execute * commands on multiple mongoses (e.g. killAllSessions) */ - self::$internalClient = new Client(static::getUri(true)); + self::$internalClient = self::createTestClient(static::getUri(true)); self::killAllSessions(); } @@ -154,6 +154,19 @@ public function provideCrudTests() return $this->provideTests(__DIR__ . '/crud'); } + /** + * @dataProvider provideVersionedApiTests + */ + public function testVersionedApi(...$args) + { + $this->doTestCase(...$args); + } + + public function provideVersionedApiTests() + { + return $this->provideTests(__DIR__ . '/versioned-api'); + } + /** * @dataProvider providePassingTests */ @@ -252,17 +265,35 @@ private function checkRunOnRequirements(array $runOnRequirements) $serverVersion = $this->getCachedServerVersion(); $topology = $this->getCachedTopology(); + $serverParameters = $this->getCachedServerParameters(); foreach ($runOnRequirements as $o) { $runOnRequirement = new RunOnRequirement($o); - if ($runOnRequirement->isSatisfied($serverVersion, $topology)) { + if ($runOnRequirement->isSatisfied($serverVersion, $topology, $serverParameters)) { return; } } + // @todo Add server parameter requirements? $this->markTestSkipped(sprintf('Server version "%s" and topology "%s" do not meet test requirements', $serverVersion, $topology)); } + /** + * Return the server parameters (cached for subsequent calls). + */ + private function getCachedServerParameters() + { + static $cachedServerParameters; + + if (isset($cachedServerParameters)) { + return $cachedServerParameters; + } + + $cachedServerParameters = $this->getServerParameters(); + + return $cachedServerParameters; + } + /** * Return the server version (cached for subsequent calls). * @@ -317,6 +348,19 @@ private function getCachedTopology() return $cachedTopology; } + private function getServerParameters() + { + $cursor = $this->manager->executeCommand( + 'admin', + new Command(['getParameter' => '*']), + new ReadPreference(ReadPreference::RP_PRIMARY) + ); + + $cursor->rewind(); + + return $cursor->current(); + } + /** * Checks is a test format schema version is supported. * diff --git a/tests/UnifiedSpecTests/valid-fail/entity-client-apiVersion-unsupported.json b/tests/UnifiedSpecTests/valid-fail/entity-client-apiVersion-unsupported.json new file mode 100644 index 000000000..d92d23dca --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/entity-client-apiVersion-unsupported.json @@ -0,0 +1,20 @@ +{ + "description": "entity-client-apiVersion-unsupported", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "serverApi": { + "version": "server_will_never_support_this_api_version" + } + } + } + ], + "tests": [ + { + "description": "foo", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json b/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json index dc6e332e3..2a2c41a68 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json @@ -103,6 +103,9 @@ { "name": "createChangeStream", "object": "client0", + "arguments": { + "pipeline": [] + }, "saveResultAsEntity": "changeStream0" }, { @@ -246,7 +249,8 @@ "name": "createChangeStream", "object": "collection0", "arguments": { - "batchSize": 1 + "batchSize": 1, + "pipeline": [] }, "saveResultAsEntity": "changeStream0" }, diff --git a/tests/UnifiedSpecTests/valid-pass/poc-gridfs.json b/tests/UnifiedSpecTests/valid-pass/poc-gridfs.json index c04ed89a7..1f07a19bf 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-gridfs.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-gridfs.json @@ -240,7 +240,9 @@ "uploadDate": { "$$type": "date" }, - "md5": "283d4fea5dded59cf837d3047328f5af", + "md5": { + "$$unsetOrMatches": "283d4fea5dded59cf837d3047328f5af" + }, "filename": "filename" } ] diff --git a/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json b/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json index e64ce1bce..30c1d5415 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json @@ -297,11 +297,15 @@ "ordered": true }, "expectResult": { - "insertedCount": 2, - "insertedIds": { - "$$unsetOrMatches": { - "0": 3, - "1": 4 + "$$unsetOrMatches": { + "insertedCount": { + "$$unsetOrMatches": 2 + }, + "insertedIds": { + "$$unsetOrMatches": { + "0": 3, + "1": 4 + } } } } diff --git a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json new file mode 100644 index 000000000..e3bb4130b --- /dev/null +++ b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json @@ -0,0 +1,1115 @@ +{ + "description": "CRUD Api Version 1 (strict)", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent" + ], + "serverApi": { + "version": "1", + "strict": true + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "versioned-api-tests" + } + }, + { + "database": { + "id": "adminDatabase", + "client": "client", + "databaseName": "admin" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "_yamlAnchors": { + "versions": [ + { + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + ] + }, + "initialData": [ + { + "collectionName": "test", + "databaseName": "versioned-api-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + ], + "tests": [ + { + "description": "aggregate on collection appends declared API version", + "operations": [ + { + "name": "aggregate", + "object": "collection", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "aggregate on database appends declared API version", + "operations": [ + { + "name": "aggregate", + "object": "adminDatabase", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + } + ] + }, + "expectError": { + "errorCodeName": "APIStrictError" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "bulkWrite appends declared API version", + "operations": [ + { + "name": "bulkWrite", + "object": "collection", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 6, + "x": 66 + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + { + "deleteMany": { + "filter": { + "x": { + "$nin": [ + 24, + 34 + ] + } + } + } + }, + { + "updateMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 7 + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "upsert": true + } + } + ], + "ordered": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 2 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "x": { + "$nin": [ + 24, + 34 + ] + } + }, + "limit": 0 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": 7 + }, + "limit": 1 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 4 + }, + "u": { + "_id": 4, + "x": 44 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": true + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "countDocuments appends declared API version", + "operations": [ + { + "name": "countDocuments", + "object": "collection", + "arguments": { + "filter": { + "x": { + "$gt": 11 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$match": { + "x": { + "$gt": 11 + } + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "deleteMany appends declared API version", + "operations": [ + { + "name": "deleteMany", + "object": "collection", + "arguments": { + "filter": { + "x": { + "$nin": [ + 24, + 34 + ] + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "x": { + "$nin": [ + 24, + 34 + ] + } + }, + "limit": 0 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "deleteOne appends declared API version", + "operations": [ + { + "name": "deleteOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 7 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": 7 + }, + "limit": 1 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "distinct appends declared API version", + "operations": [ + { + "name": "distinct", + "object": "collection", + "arguments": { + "fieldName": "x", + "filter": {} + }, + "expectError": { + "isError": true, + "errorContains": "command distinct is not in API Version 1", + "errorCodeName": "APIStrictError" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "test", + "key": "x", + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount appends declared API version", + "skipReason": "DRIVERS-1561 collStats is not in API version 1", + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "arguments": {} + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "find command with declared API version appends to the command, but getMore does not", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": {}, + "sort": { + "_id": 1 + }, + "batchSize": 3 + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "findOneAndDelete appends declared API version", + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "remove": true, + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "findOneAndReplace appends declared API version", + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "x": 33 + }, + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "findOneAndUpdate appends declared API version", + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "insertMany appends declared API version", + "operations": [ + { + "name": "insertMany", + "object": "collection", + "arguments": { + "documents": [ + { + "_id": 6, + "x": 66 + }, + { + "_id": 7, + "x": 77 + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + }, + { + "_id": 7, + "x": 77 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "insertOne appends declared API version", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "arguments": { + "document": { + "_id": 6, + "x": 66 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "replaceOne appends declared API version", + "operations": [ + { + "name": "replaceOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "upsert": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 4 + }, + "u": { + "_id": 4, + "x": 44 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": true + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "updateMany appends declared API version", + "operations": [ + { + "name": "updateMany", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + }, + { + "description": "updateOne appends declared API version", + "operations": [ + { + "name": "updateOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 2 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json new file mode 100644 index 000000000..917185837 --- /dev/null +++ b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json @@ -0,0 +1,1106 @@ +{ + "description": "CRUD Api Version 1", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent" + ], + "serverApi": { + "version": "1", + "deprecationErrors": true + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "versioned-api-tests" + } + }, + { + "database": { + "id": "adminDatabase", + "client": "client", + "databaseName": "admin" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "_yamlAnchors": { + "versions": [ + { + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + ] + }, + "initialData": [ + { + "collectionName": "test", + "databaseName": "versioned-api-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + ], + "tests": [ + { + "description": "aggregate on collection appends declared API version", + "operations": [ + { + "name": "aggregate", + "object": "collection", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "aggregate on database appends declared API version", + "operations": [ + { + "name": "aggregate", + "object": "adminDatabase", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "bulkWrite appends declared API version", + "operations": [ + { + "name": "bulkWrite", + "object": "collection", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 6, + "x": 66 + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + { + "deleteMany": { + "filter": { + "x": { + "$nin": [ + 24, + 34 + ] + } + } + } + }, + { + "updateMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 7 + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "upsert": true + } + } + ], + "ordered": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 2 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "x": { + "$nin": [ + 24, + 34 + ] + } + }, + "limit": 0 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": 7 + }, + "limit": 1 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 4 + }, + "u": { + "_id": 4, + "x": 44 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": true + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "countDocuments appends declared API version", + "operations": [ + { + "name": "countDocuments", + "object": "collection", + "arguments": { + "filter": { + "x": { + "$gt": 11 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$match": { + "x": { + "$gt": 11 + } + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "deleteMany appends declared API version", + "operations": [ + { + "name": "deleteMany", + "object": "collection", + "arguments": { + "filter": { + "x": { + "$nin": [ + 24, + 34 + ] + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "x": { + "$nin": [ + 24, + 34 + ] + } + }, + "limit": 0 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "deleteOne appends declared API version", + "operations": [ + { + "name": "deleteOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 7 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": 7 + }, + "limit": 1 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "distinct appends declared API version", + "operations": [ + { + "name": "distinct", + "object": "collection", + "arguments": { + "fieldName": "x", + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "test", + "key": "x", + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount appends declared API version on 4.9.0 or greater", + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "arguments": {} + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "find command with declared API version appends to the command, but getMore does not", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": {}, + "sort": { + "_id": 1 + }, + "batchSize": 3 + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "findOneAndDelete appends declared API version", + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "remove": true, + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "findOneAndReplace appends declared API version", + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "x": 33 + }, + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "findOneAndUpdate appends declared API version", + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "insertMany appends declared API version", + "operations": [ + { + "name": "insertMany", + "object": "collection", + "arguments": { + "documents": [ + { + "_id": 6, + "x": 66 + }, + { + "_id": 7, + "x": 77 + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + }, + { + "_id": 7, + "x": 77 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "insertOne appends declared API version", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "arguments": { + "document": { + "_id": 6, + "x": 66 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "replaceOne appends declared API version", + "operations": [ + { + "name": "replaceOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 4 + }, + "replacement": { + "_id": 4, + "x": 44 + }, + "upsert": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 4 + }, + "u": { + "_id": 4, + "x": 44 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": true + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "updateMany appends declared API version", + "operations": [ + { + "name": "updateMany", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + }, + { + "description": "updateOne appends declared API version", + "operations": [ + { + "name": "updateOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 2 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json b/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json new file mode 100644 index 000000000..e901887e4 --- /dev/null +++ b/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json @@ -0,0 +1,117 @@ +{ + "description": "RunCommand helper: No API version declared", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.9", + "serverParameters": { + "requireApiVersion": false + } + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "versioned-api-tests" + } + } + ], + "tests": [ + { + "description": "runCommand does not inspect or change the command document", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1, + "apiVersion": "server_will_never_support_this_api_version" + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "ping": 1, + "apiVersion": "server_will_never_support_this_api_version", + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + }, + "commandName": "ping", + "databaseName": "versioned-api-tests" + } + } + ] + } + ] + }, + { + "description": "runCommand does not prevent sending invalid API version declarations", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1, + "apiStrict": true + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "ping": 1, + "apiVersion": { + "$$exists": false + }, + "apiStrict": true, + "apiDeprecationErrors": { + "$$exists": false + } + }, + "commandName": "ping", + "databaseName": "versioned-api-tests" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json b/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json new file mode 100644 index 000000000..6dc59a045 --- /dev/null +++ b/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json @@ -0,0 +1,74 @@ +{ + "description": "Test commands: deprecation errors", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.9", + "serverParameters": { + "enableTestCommands": true, + "acceptAPIVersion2": true, + "requireApiVersion": false + } + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "versioned-api-tests" + } + } + ], + "tests": [ + { + "description": "Running a command that is deprecated raises a deprecation error", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "testDeprecationInVersion2", + "command": { + "testDeprecationInVersion2": 1, + "apiVersion": "2", + "apiDeprecationErrors": true + } + }, + "expectError": { + "isError": true, + "errorContains": "command testDeprecationInVersion2 is deprecated in API Version 2", + "errorCodeName": "APIDeprecationError" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "testDeprecationInVersion2": 1, + "apiVersion": "2", + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": true + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json b/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json new file mode 100644 index 000000000..1705ba7bf --- /dev/null +++ b/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json @@ -0,0 +1,74 @@ +{ + "description": "Test commands: strict mode", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.9", + "serverParameters": { + "enableTestCommands": true + } + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent" + ], + "serverApi": { + "version": "1", + "strict": true + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "versioned-api-tests" + } + } + ], + "tests": [ + { + "description": "Running a command that is not part of the versioned API results in an error", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "testVersion2", + "command": { + "testVersion2": 1 + } + }, + "expectError": { + "isError": true, + "errorContains": "command testVersion2 is not in API Version 1", + "errorCodeName": "APIStrictError" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "testVersion2": 1, + "apiVersion": "1", + "apiStrict": true, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/versioned-api/transaction-handling.json b/tests/UnifiedSpecTests/versioned-api/transaction-handling.json new file mode 100644 index 000000000..a740405d3 --- /dev/null +++ b/tests/UnifiedSpecTests/versioned-api/transaction-handling.json @@ -0,0 +1,519 @@ +{ + "description": "Transaction handling", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.9", + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent" + ], + "serverApi": { + "version": "1" + } + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "versioned-api-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + }, + { + "session": { + "id": "session", + "client": "client" + } + } + ], + "_yamlAnchors": { + "versions": [ + { + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + }, + { + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + ] + }, + "initialData": [ + { + "collectionName": "test", + "databaseName": "versioned-api-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + ], + "tests": [ + { + "description": "Only the first command in a transaction declares an API version", + "runOnRequirements": [ + { + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], + "operations": [ + { + "name": "startTransaction", + "object": "session" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session", + "document": { + "_id": 6, + "x": 66 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 6 + } + } + } + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session", + "document": { + "_id": 7, + "x": 77 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 7 + } + } + } + }, + { + "name": "commitTransaction", + "object": "session" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "lsid": { + "$$sessionLsid": "session" + }, + "startTransaction": true, + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 7, + "x": 77 + } + ], + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "Committing a transaction twice does not append server API options", + "runOnRequirements": [ + { + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], + "operations": [ + { + "name": "startTransaction", + "object": "session" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session", + "document": { + "_id": 6, + "x": 66 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 6 + } + } + } + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session", + "document": { + "_id": 7, + "x": 77 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 7 + } + } + } + }, + { + "name": "commitTransaction", + "object": "session" + }, + { + "name": "commitTransaction", + "object": "session" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "lsid": { + "$$sessionLsid": "session" + }, + "startTransaction": true, + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 7, + "x": 77 + } + ], + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "abortTransaction does not include an API version", + "runOnRequirements": [ + { + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], + "operations": [ + { + "name": "startTransaction", + "object": "session" + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session", + "document": { + "_id": 6, + "x": 66 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 6 + } + } + } + }, + { + "name": "insertOne", + "object": "collection", + "arguments": { + "session": "session", + "document": { + "_id": 7, + "x": 77 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 7 + } + } + } + }, + { + "name": "abortTransaction", + "object": "session" + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 6, + "x": 66 + } + ], + "lsid": { + "$$sessionLsid": "session" + }, + "startTransaction": true, + "apiVersion": "1", + "apiStrict": { + "$$unsetOrMatches": false + }, + "apiDeprecationErrors": { + "$$unsetOrMatches": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 7, + "x": 77 + } + ], + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": 1, + "lsid": { + "$$sessionLsid": "session" + }, + "apiVersion": { + "$$exists": false + }, + "apiStrict": { + "$$exists": false + }, + "apiDeprecationErrors": { + "$$exists": false + } + } + } + } + ] + } + ] + } + ] +} From 21e7ecde42e45d98ced06c6818495289c1e2e916 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 31 Mar 2021 08:05:58 +0200 Subject: [PATCH 026/321] PHPLIB-621 Document Versioned API usage (#815) * Move non-deprecated driver options to the top * Document versioned API usage * Document serverApi driver option * Apply suggestions from code review Co-authored-by: Jeremy Mikola Co-authored-by: Jeremy Mikola --- ...Client-method-construct-driverOptions.yaml | 96 +++++++++++-------- docs/tutorial.txt | 1 + docs/tutorial/versioned-api.txt | 94 ++++++++++++++++++ 3 files changed, 149 insertions(+), 42 deletions(-) create mode 100644 docs/tutorial/versioned-api.txt diff --git a/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml b/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml index 77520c0d2..f47e56ba1 100644 --- a/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml @@ -1,4 +1,58 @@ arg_name: option +name: autoEncryption +type: array +description: | + Options to configure client-side field-level encryption in the driver. The + encryption options are documented in the :php:`extension documentation + `. + For the ``keyVaultClient`` option, you may pass a :phpclass:`MongoDB\\Client` + instance, which will be unwrapped to provide a :php:`MongoDB\\Driver\\Manager ` + to the extension. + .. versionadded:: 1.6 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: driver +type: array +description: | + Additional driver metadata to be passed on to the server handshake. This is an + array containing ``name``, ``version``, and ``platform`` fields: + + .. code-block:: php + + [ + 'name' => 'my-driver', + 'version' => '1.2.3-dev', + 'platform' => 'some-platform', + ] + + .. note:: + + This feature is primarily designed for custom drivers and ODMs, which may + want to identify themselves to the server for diagnostic purposes. + Applications should use the ``appName`` URI option instead of driver + metadata. + + .. versionadded:: 1.7 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: serverApi +type: :php:`MongoDB\\Driver\\ServerApi ` +description: | + Used to declare an API version on the client. See the + :manual:`Versioned API tutorial ` for usage. + + .. versionadded:: 1.9 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: typeMap type: array description: | @@ -131,46 +185,4 @@ description: | interface: phpmethod operation: ~ optional: true ---- -arg_name: option -name: autoEncryption -type: array -description: | - Options to configure client-side field-level encryption in the driver. The - encryption options are documented in the :php:`extension documentation - `. - For the ``keyVaultClient`` option, you may pass a :phpclass:`MongoDB\\Client` - instance, which will be unwrapped to provide a :php:`MongoDB\\Driver\\Manager ` - to the extension. - .. versionadded:: 1.6 -interface: phpmethod -operation: ~ -optional: true ---- -arg_name: option -name: driver -type: array -description: | - Additional driver metadata to be passed on to the server handshake. This is an - array containing ``name``, ``version``, and ``platform`` fields: - - .. code-block:: php - - [ - 'name' => 'my-driver', - 'version' => '1.2.3-dev', - 'platform' => 'some-platform', - ] - - .. note:: - - This feature is primarily designed for custom drivers and ODMs, which may - want to identify themselves to the server for diagnostic purposes. - Applications should use the ``appName`` URI option instead of driver - metadata. - - .. versionadded:: 1.7 -interface: phpmethod -operation: ~ -optional: true ... diff --git a/docs/tutorial.txt b/docs/tutorial.txt index 7735508e6..6ad6400ab 100644 --- a/docs/tutorial.txt +++ b/docs/tutorial.txt @@ -15,3 +15,4 @@ Tutorials /tutorial/indexes /tutorial/tailable-cursor /tutorial/example-data + /tutorial/versioned-api diff --git a/docs/tutorial/versioned-api.txt b/docs/tutorial/versioned-api.txt new file mode 100644 index 000000000..ebe971d11 --- /dev/null +++ b/docs/tutorial/versioned-api.txt @@ -0,0 +1,94 @@ +============= +Versioned API +============= + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Declaring an API version +------------------------ + +To declare an API version, pass a ``serverApi`` driver option when creating your +client. The value is a +:php:`MongoDB\\Driver\\ServerApi ` instance that +contains API version information. This feature is introduced in MongoDB 5.0, +which will initially support only API version "1". Additional versions may be +introduced in future versions of the server. + +.. code-block:: php + + $serverApi]); + + // Command includes the declared API version + $client->database->collection->find([]); + +.. note:: + + Only declare an API version when connecting to a deployment that has no + pre-5.0 members. Older servers will error when encountering commands with a + declared API version. + +Strict API +---------- + +By default, declaring an API version guarantees behavior for commands that are +part of the versioned API, but does not forbid using commands that are not part +of the API version. To only allow commands and options that are part of the +versioned API, specify the ``strict`` option when creating the +specify the ``strict`` option when creating the +:php:`MongoDB\\Driver\\ServerApi ` instance: + +.. code-block:: php + + $serverApi]); + + // Will fail as the tailable option is not supported in versioned API + $client->database->collection->find([], ['tailable' => true]); + +Fail on Deprecated Commands +--------------------------- + +The optional ``deprecationErrors`` option causes MongoDB to fail all commands +or behaviors that have been deprecated in the API version. This can be used in +testing to ensure a smooth transition to a future API version. + +.. code-block:: php + + $serverApi]); + +.. note:: + + At the time of this writing, no part of API version "1" has been deprecated. + +Usage with the command helper +----------------------------- + +When using the :phpmethod:`MongoDB\\Database::command()` method to run arbitrary +commands, the API version declared to the client is automatically appended to +the command document. Setting any of the ``apiVersion``, ``apiStrict``, or +``apiDeprecationErrors`` command options in the command document and calling +:phpmethod:`MongoDB\\Database::command()` from a client with a declared API +version is not supported and will lead to undefined behavior. From 027134d41564aef94dbb13ed092802521bca4343 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 31 Mar 2021 14:22:27 +0200 Subject: [PATCH 027/321] PHPLIB-637 Remove xtrace from build scripts (#817) --- .evergreen/compile-unix.sh | 1 - .evergreen/compile-windows.sh | 1 - .evergreen/compile.sh | 1 - .evergreen/config.yml | 2 -- .evergreen/download-mongodb.sh | 1 - .evergreen/make-docs.sh | 1 - .evergreen/make-release.sh | 1 - .evergreen/run-atlas-proxy.sh | 1 - .evergreen/run-orchestration.sh | 1 - .evergreen/start-orchestration.sh | 1 - .evergreen/stop-orchestration.sh | 1 - 11 files changed, 12 deletions(-) diff --git a/.evergreen/compile-unix.sh b/.evergreen/compile-unix.sh index 7591c3241..459642b6f 100755 --- a/.evergreen/compile-unix.sh +++ b/.evergreen/compile-unix.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail # Supported/used environment variables: diff --git a/.evergreen/compile-windows.sh b/.evergreen/compile-windows.sh index 33349bb34..10d207276 100755 --- a/.evergreen/compile-windows.sh +++ b/.evergreen/compile-windows.sh @@ -1,6 +1,5 @@ #!/bin/sh set -o igncr # Ignore CR in this script -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail # Supported/used environment variables: diff --git a/.evergreen/compile.sh b/.evergreen/compile.sh index 8b7820e99..575ff1bbc 100755 --- a/.evergreen/compile.sh +++ b/.evergreen/compile.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 99457c07f..dc434c123 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -64,7 +64,6 @@ functions: PROJECT_DIRECTORY: "$PROJECT_DIRECTORY" PREPARE_SHELL: | set -o errexit - set -o xtrace export DRIVERS_TOOLS="$DRIVERS_TOOLS" export MONGO_ORCHESTRATION_HOME="$MONGO_ORCHESTRATION_HOME" export MONGODB_BINARIES="$MONGODB_BINARIES" @@ -289,7 +288,6 @@ tasks: type: test params: script: | - set -o xtrace . ${DRIVERS_TOOLS}/.evergreen/download-mongodb.sh || true get_distro || true echo $DISTRO diff --git a/.evergreen/download-mongodb.sh b/.evergreen/download-mongodb.sh index 26238667d..cc7d3457f 100755 --- a/.evergreen/download-mongodb.sh +++ b/.evergreen/download-mongodb.sh @@ -2,7 +2,6 @@ #For future use the feed to get full list of distros : http://downloads.mongodb.org/full.json -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail get_distro () diff --git a/.evergreen/make-docs.sh b/.evergreen/make-docs.sh index f61da5a4b..2bff9aa0a 100644 --- a/.evergreen/make-docs.sh +++ b/.evergreen/make-docs.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail diff --git a/.evergreen/make-release.sh b/.evergreen/make-release.sh index ef6e2af7e..e81187caa 100644 --- a/.evergreen/make-release.sh +++ b/.evergreen/make-release.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail diff --git a/.evergreen/run-atlas-proxy.sh b/.evergreen/run-atlas-proxy.sh index edfdb7bc9..35abb865b 100755 --- a/.evergreen/run-atlas-proxy.sh +++ b/.evergreen/run-atlas-proxy.sh @@ -28,7 +28,6 @@ # MONGODB_VERSION - version of MongoDB to download and use. For Atlas # Proxy, must be "3.4" or "latest". Defaults to "3.4". -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail MONGODB_VERSION=${MONGODB_VERSION:-"3.4"} diff --git a/.evergreen/run-orchestration.sh b/.evergreen/run-orchestration.sh index d969aad16..ed87d8e22 100755 --- a/.evergreen/run-orchestration.sh +++ b/.evergreen/run-orchestration.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail diff --git a/.evergreen/start-orchestration.sh b/.evergreen/start-orchestration.sh index 2197f2d40..e593b17ff 100644 --- a/.evergreen/start-orchestration.sh +++ b/.evergreen/start-orchestration.sh @@ -6,7 +6,6 @@ if [ "$#" -ne 1 ]; then exit 1 fi -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail diff --git a/.evergreen/stop-orchestration.sh b/.evergreen/stop-orchestration.sh index 5c01d1580..c30eeed5e 100755 --- a/.evergreen/stop-orchestration.sh +++ b/.evergreen/stop-orchestration.sh @@ -1,5 +1,4 @@ #!/bin/sh -set -o xtrace # Write all commands first to stderr set -o errexit # Exit the script with error if any of the commands fail cd "$MONGO_ORCHESTRATION_HOME" From 8123216f21d31a2a5b845aa91fba7a182d060509 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 9 Apr 2021 14:02:02 +0200 Subject: [PATCH 028/321] Test against 1.10.0alpha1 on evergreen --- .evergreen/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 4dea223cc..22fdfb518 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -463,10 +463,10 @@ axes: # * latest-stable can be updated when we start tagging 1.10 releases (even beta) # * 1.10-dev can be enabled once 1.10 has been branched # * latest-dev can be enabled once 1.10 has been branched -# - id: "lowest-supported" -# display_name: "1.10-dev (master)" -# variables: -# EXTENSION_BRANCH: "master" + - id: "lowest-supported" + display_name: "1.10.0-alpha1" + variables: + EXTENSION_VERSION: "1.10.0alpha1" - id: "latest" display_name: "1.10-dev (master)" variables: From 371879b891c4deed04c7d3af0fb79d28eb9329cd Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 20 Apr 2021 09:21:00 -0400 Subject: [PATCH 029/321] Add external links to new issue workflow (#821) --- .github/ISSUE_TEMPLATE/bug-report.md | 2 +- .github/ISSUE_TEMPLATE/config.yml | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index fa2163dbb..888e539ed 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,6 +1,6 @@ --- name: Bug Report -about: Create a report to help us improve +about: Report a bug for the MongoDB PHP library. title: '' labels: '' assignees: '' diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..4ab6a78f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,12 @@ +blank_issues_enabled: false + +contact_links: + - name: New issue on mongodb/mongo-php-driver + url: https://github.com/mongodb/mongo-php-driver/issues/new/choose + about: Experiencing a problem with the MongoDB PHP extension? Please report it through the mongo-php-driver repository. + - name: MongoDB Developer Community Forums + url: https://developer.mongodb.com/community/forums/ + about: For questions, discussions, or general technical support, visit the MongoDB Community Forums. The MongoDB Community Forums are a centralized place to connect with other MongoDB users, ask questions, and get answers. + - name: Report a Security Vulnerability + url: https://docs.mongodb.org/manual/tutorial/create-a-vulnerability-report + about: If you believe you have discovered a vulnerability in MongoDB products or have experienced a security incident related to MongoDB products, please report the issue to aid in its resolution. From a54358b423202703b430c3f0597702811dbaab93 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 22 Apr 2021 10:46:20 -0400 Subject: [PATCH 030/321] PHPLIB-644: Unified GridFS tests (#819) Synced with mongodb/specifications@c5813a4891c33d085a4bebd96b474bfca20cfd63 Also fix Bucket method for downloadByName operation and remove legacy GridFS spec tests and runner. --- tests/GridFS/SpecFunctionalTest.php | 388 --------- tests/GridFS/spec-tests/delete.json | 291 ------- tests/GridFS/spec-tests/download.json | 467 ---------- tests/GridFS/spec-tests/download_by_name.json | 240 ------ tests/GridFS/spec-tests/upload.json | 466 ---------- tests/UnifiedSpecTests/Operation.php | 2 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 + tests/UnifiedSpecTests/gridfs/delete.json | 799 ++++++++++++++++++ tests/UnifiedSpecTests/gridfs/download.json | 558 ++++++++++++ .../gridfs/downloadByName.json | 330 ++++++++ .../gridfs/upload-disableMD5.json | 172 ++++ tests/UnifiedSpecTests/gridfs/upload.json | 616 ++++++++++++++ 12 files changed, 2489 insertions(+), 1853 deletions(-) delete mode 100644 tests/GridFS/SpecFunctionalTest.php delete mode 100644 tests/GridFS/spec-tests/delete.json delete mode 100644 tests/GridFS/spec-tests/download.json delete mode 100644 tests/GridFS/spec-tests/download_by_name.json delete mode 100644 tests/GridFS/spec-tests/upload.json create mode 100644 tests/UnifiedSpecTests/gridfs/delete.json create mode 100644 tests/UnifiedSpecTests/gridfs/download.json create mode 100644 tests/UnifiedSpecTests/gridfs/downloadByName.json create mode 100644 tests/UnifiedSpecTests/gridfs/upload-disableMD5.json create mode 100644 tests/UnifiedSpecTests/gridfs/upload.json diff --git a/tests/GridFS/SpecFunctionalTest.php b/tests/GridFS/SpecFunctionalTest.php deleted file mode 100644 index 6d08e0ef9..000000000 --- a/tests/GridFS/SpecFunctionalTest.php +++ /dev/null @@ -1,388 +0,0 @@ -expectedFilesCollection = new Collection($this->manager, $this->getDatabaseName(), 'expected.files'); - $this->expectedFilesCollection->drop(); - - $this->expectedChunksCollection = new Collection($this->manager, $this->getDatabaseName(), 'expected.chunks'); - $this->expectedChunksCollection->drop(); - } - - /** - * @dataProvider provideSpecificationTests - */ - public function testSpecification(array $initialData, array $test) - { - $this->initializeData($initialData); - - if (isset($test['arrange'])) { - foreach ($test['arrange']['data'] as $dataModification) { - $this->executeDataModification($dataModification); - } - } - - try { - $result = $this->executeAct($test['act']); - } catch (Throwable $e) { - $result = $e; - } - - /* Per the GridFS spec: "Drivers MAY attempt to delete any orphaned - * chunks with files_id equal to id before raising the error." The spec - * tests do not expect orphaned chunks to be removed, so we manually - * remove those chunks from the expected collection. */ - if ($test['act']['operation'] === 'delete' && $result instanceof FileNotFoundException) { - $filesId = $this->convertTypes($test['act'])['arguments']['id']; - $this->expectedChunksCollection->deleteMany(['files_id' => $filesId]); - } - - if (isset($test['assert'])) { - $this->executeAssert($test['assert'], $result); - } - } - - public function provideSpecificationTests() - { - $testArgs = []; - - foreach (glob(__DIR__ . '/spec-tests/*.json') as $filename) { - $json = json_decode(file_get_contents($filename), true); - - foreach ($json['tests'] as $test) { - $name = str_replace(' ', '_', $test['description']); - $testArgs[$name] = [$json['data'], $test]; - } - } - - return $testArgs; - } - - /** - * Assert that the collections contain equivalent documents. - * - * This method will resolve references within the expected collection's - * documents before comparing documents. Occurrences of "*result" in the - * expected collection's documents will be replaced with the actual result. - * Occurrences of "*actual" in the expected collection's documents will be - * replaced with the corresponding value in the actual collection's document - * being compared. - * - * @param Collection $expectedCollection - * @param Collection $actualCollection - * @param mixed $actualResult - */ - private function assertEquivalentCollections($expectedCollection, $actualCollection, $actualResult) - { - $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - $mi->attachIterator($expectedCollection->find()); - $mi->attachIterator($actualCollection->find()); - - foreach ($mi as $documents) { - list($expectedDocument, $actualDocument) = $documents; - - foreach ($expectedDocument as $key => $value) { - if (! is_string($value)) { - continue; - } - - if ($value === '*result') { - $expectedDocument[$key] = $actualResult; - } - - if (! strncmp($value, '*actual_', 8)) { - $expectedDocument[$key] = $actualDocument[$key]; - } - } - - $this->assertSameDocument($expectedDocument, $actualDocument); - } - } - - /** - * Convert encoded types in the array and return the modified array. - * - * Nested arrays with "$oid" and "$date" keys will be converted to ObjectId - * and UTCDateTime instances, respectively. Nested arrays with "$hex" keys - * will be converted to a string or Binary object. - * - * @param param $data - * @param boolean $createBinary If true, convert "$hex" values to a Binary - * @return array - */ - private function convertTypes(array $data, $createBinary = true) - { - /* array_walk_recursive() only visits leaf nodes within the array, so we - * need to manually recurse. - */ - array_walk($data, function (&$value) use ($createBinary) { - if (! is_array($value)) { - return; - } - - if (isset($value['$oid'])) { - $value = new ObjectId($value['$oid']); - - return; - } - - if (isset($value['$hex'])) { - $value = $createBinary - ? new Binary(hex2bin($value['$hex']), Binary::TYPE_GENERIC) - : hex2bin($value['$hex']); - - return; - } - - if (isset($value['$date'])) { - $value = new UTCDateTime(new DateTime($value['$date'])); - - return; - } - - $value = $this->convertTypes($value, $createBinary); - }); - - return $data; - } - - /** - * Executes an "act" block. - * - * @param array $act - * @return mixed - * @throws LogicException if the operation is unsupported - */ - private function executeAct(array $act) - { - $act = $this->convertTypes($act, false); - - switch ($act['operation']) { - case 'delete': - return $this->bucket->delete($act['arguments']['id']); - case 'download': - return stream_get_contents($this->bucket->openDownloadStream($act['arguments']['id'])); - case 'download_by_name': - return stream_get_contents($this->bucket->openDownloadStreamByName( - $act['arguments']['filename'], - $act['arguments']['options'] ?? [] - )); - case 'upload': - return $this->bucket->uploadFromStream( - $act['arguments']['filename'], - $this->createStream($act['arguments']['source']), - $act['arguments']['options'] ?? [] - ); - default: - throw new LogicException('Unsupported act: ' . $act['operation']); - } - } - - /** - * Executes an "assert" block. - * - * @param array $assert - * @param mixed $actualResult - * @return mixed - * @throws LogicException if the operation is unsupported - */ - private function executeAssert(array $assert, $actualResult) - { - if (isset($assert['error'])) { - $this->assertInstanceOf($this->getExceptionClassForError($assert['error']), $actualResult); - } - - if (isset($assert['result'])) { - $this->executeAssertResult($assert['result'], $actualResult); - } - - if (! isset($assert['data'])) { - return; - } - - /* Since "*actual" may be used for an expected document's "_id", append - * a unique value to avoid duplicate key exceptions. - */ - array_walk_recursive($assert['data'], function (&$value) { - if ($value === '*actual') { - $value .= '_' . new ObjectId(); - } - }); - - foreach ($assert['data'] as $dataModification) { - $this->executeDataModification($dataModification); - } - - $this->assertEquivalentCollections($this->expectedFilesCollection, $this->filesCollection, $actualResult); - $this->assertEquivalentCollections($this->expectedChunksCollection, $this->chunksCollection, $actualResult); - } - - /** - * Executes the "result" section of an "assert" block. - * - * @param mixed $expectedResult - * @param mixed $actualResult - * @throws LogicException if the result assertion is unsupported - */ - private function executeAssertResult($expectedResult, $actualResult) - { - if ($expectedResult === 'void') { - return $this->assertNull($actualResult); - } - - if ($expectedResult === '&result') { - // Do nothing; assertEquivalentCollections() will handle this - return; - } - - if (isset($expectedResult['$hex'])) { - return $this->assertSame(hex2bin($expectedResult['$hex']), $actualResult); - } - - throw new LogicException('Unsupported result assertion: ' . var_export($expectedResult, true)); - } - - /** - * Executes a data modification from an "arrange" or "assert" block. - * - * @param array $dataModification - * @return mixed - * @throws LogicException if the operation or collection is unsupported - */ - private function executeDataModification(array $dataModification) - { - if (empty($dataModification)) { - throw new LogicException('Command for data modification is empty'); - } - - foreach ($dataModification as $type => $collectionName) { - break; - } - - if (! in_array($collectionName, ['fs.files', 'fs.chunks', 'expected.files', 'expected.chunks'])) { - throw new LogicException('Unsupported collection: ' . $collectionName); - } - - $dataModification = $this->convertTypes($dataModification); - $operations = []; - - switch ($type) { - case 'delete': - foreach ($dataModification['deletes'] as $delete) { - $operations[] = [ ($delete['limit'] === 1 ? 'deleteOne' : 'deleteMany') => [ $delete['q'] ] ]; - } - - break; - - case 'insert': - foreach ($dataModification['documents'] as $document) { - $operations[] = [ 'insertOne' => [ $document ] ]; - } - - break; - - case 'update': - foreach ($dataModification['updates'] as $update) { - $operations[] = [ 'updateOne' => [ $update['q'], $update['u'] ] ]; - } - - break; - - default: - throw new LogicException('Unsupported arrangement: ' . $type); - } - - $bulk = new BulkWrite($this->getDatabaseName(), $collectionName, $operations); - - return $bulk->execute($this->getPrimaryServer()); - } - - /** - * Returns the exception class for the "error" section of an "assert" block. - * - * @param string $error - * @return string - * @throws LogicException if the error is unsupported - */ - private function getExceptionClassForError($error) - { - switch ($error) { - case 'FileNotFound': - case 'RevisionNotFound': - return FileNotFoundException::class; - case 'ChunkIsMissing': - case 'ChunkIsWrongSize': - /* Although ReadableStream throws a CorruptFileException, the - * stream wrapper will convert it to a PHP error of type - * E_USER_WARNING. */ - return Warning::class; - default: - throw new LogicException('Unsupported error: ' . $error); - } - } - - /** - * Initializes data in the files and chunks collections. - * - * @param array $data - */ - private function initializeData(array $data) - { - $data = $this->convertTypes($data); - - if (! empty($data['files'])) { - $this->filesCollection->insertMany($data['files']); - $this->expectedFilesCollection->insertMany($data['files']); - } - - if (! empty($data['chunks'])) { - $this->chunksCollection->insertMany($data['chunks']); - $this->expectedChunksCollection->insertMany($data['chunks']); - } - } -} diff --git a/tests/GridFS/spec-tests/delete.json b/tests/GridFS/spec-tests/delete.json deleted file mode 100644 index d74e49284..000000000 --- a/tests/GridFS/spec-tests/delete.json +++ /dev/null @@ -1,291 +0,0 @@ -{ - "data": { - "files": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "length": 0, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "length-0", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "length": 0, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "length-0-with-empty-chunk", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "length": 2, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "c700ed4fdb1d27055aa3faa2c2432283", - "filename": "length-2", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "length": 8, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "dd254cdc958e53abaa67da9f797125f5", - "filename": "length-8", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - } - ], - "chunks": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "files_id": { - "$oid": "000000000000000000000002" - }, - "n": 0, - "data": { - "$hex": "" - } - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "files_id": { - "$oid": "000000000000000000000003" - }, - "n": 0, - "data": { - "$hex": "1122" - } - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 1, - "data": { - "$hex": "55667788" - } - } - ] - }, - "tests": [ - { - "description": "Delete when length is 0", - "act": { - "operation": "delete", - "arguments": { - "id": { - "$oid": "000000000000000000000001" - } - } - }, - "assert": { - "result": "void", - "data": [ - { - "delete": "expected.files", - "deletes": [ - { - "q": { - "_id": { - "$oid": "000000000000000000000001" - } - }, - "limit": 1 - } - ] - } - ] - } - }, - { - "description": "Delete when length is 0 and there is one extra empty chunk", - "act": { - "operation": "delete", - "arguments": { - "id": { - "$oid": "000000000000000000000002" - } - } - }, - "assert": { - "result": "void", - "data": [ - { - "delete": "expected.files", - "deletes": [ - { - "q": { - "_id": { - "$oid": "000000000000000000000002" - } - }, - "limit": 1 - } - ] - }, - { - "delete": "expected.chunks", - "deletes": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000002" - } - }, - "limit": 0 - } - ] - } - ] - } - }, - { - "description": "Delete when length is 8", - "act": { - "operation": "delete", - "arguments": { - "id": { - "$oid": "000000000000000000000004" - } - } - }, - "assert": { - "result": "void", - "data": [ - { - "delete": "expected.files", - "deletes": [ - { - "q": { - "_id": { - "$oid": "000000000000000000000004" - } - }, - "limit": 1 - } - ] - }, - { - "delete": "expected.chunks", - "deletes": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000004" - } - }, - "limit": 0 - } - ] - } - ] - } - }, - { - "description": "Delete when files entry does not exist", - "act": { - "operation": "delete", - "arguments": { - "id": { - "$oid": "000000000000000000000000" - } - } - }, - "assert": { - "error": "FileNotFound" - } - }, - { - "description": "Delete when files entry does not exist and there are orphaned chunks", - "arrange": { - "data": [ - { - "delete": "fs.files", - "deletes": [ - { - "q": { - "_id": { - "$oid": "000000000000000000000004" - } - }, - "limit": 1 - } - ] - } - ] - }, - "act": { - "operation": "delete", - "arguments": { - "id": { - "$oid": "000000000000000000000004" - } - } - }, - "assert": { - "error": "FileNotFound", - "data": [ - { - "delete": "expected.files", - "deletes": [ - { - "q": { - "_id": { - "$oid": "000000000000000000000004" - } - }, - "limit": 1 - } - ] - } - ] - } - } - ] -} diff --git a/tests/GridFS/spec-tests/download.json b/tests/GridFS/spec-tests/download.json deleted file mode 100644 index 5092fba98..000000000 --- a/tests/GridFS/spec-tests/download.json +++ /dev/null @@ -1,467 +0,0 @@ -{ - "data": { - "files": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "length": 0, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "length-0", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "length": 0, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "length-0-with-empty-chunk", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "length": 2, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "c700ed4fdb1d27055aa3faa2c2432283", - "filename": "length-2", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "length": 8, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "dd254cdc958e53abaa67da9f797125f5", - "filename": "length-8", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000005" - }, - "length": 10, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "57d83cd477bfb1ccd975ab33d827a92b", - "filename": "length-10", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000006" - }, - "length": 2, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "c700ed4fdb1d27055aa3faa2c2432283", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - } - ], - "chunks": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "files_id": { - "$oid": "000000000000000000000002" - }, - "n": 0, - "data": { - "$hex": "" - } - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "files_id": { - "$oid": "000000000000000000000003" - }, - "n": 0, - "data": { - "$hex": "1122" - } - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 1, - "data": { - "$hex": "55667788" - } - }, - { - "_id": { - "$oid": "000000000000000000000005" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": { - "$oid": "000000000000000000000006" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1, - "data": { - "$hex": "55667788" - } - }, - { - "_id": { - "$oid": "000000000000000000000007" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 2, - "data": { - "$hex": "99aa" - } - }, - { - "_id": { - "$oid": "000000000000000000000008" - }, - "files_id": { - "$oid": "000000000000000000000006" - }, - "n": 0, - "data": { - "$hex": "1122" - } - } - ] - }, - "tests": [ - { - "description": "Download when length is zero", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000001" - }, - "options": {} - } - }, - "assert": { - "result": { - "$hex": "" - } - } - }, - { - "description": "Download when length is zero and there is one empty chunk", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000002" - }, - "options": {} - } - }, - "assert": { - "result": { - "$hex": "" - } - } - }, - { - "description": "Download when there is one chunk", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000003" - }, - "options": {} - } - }, - "assert": { - "result": { - "$hex": "1122" - } - } - }, - { - "description": "Download when there are two chunks", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000004" - }, - "options": {} - } - }, - "assert": { - "result": { - "$hex": "1122334455667788" - } - } - }, - { - "description": "Download when there are three chunks", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - }, - "options": {} - } - }, - "assert": { - "result": { - "$hex": "112233445566778899aa" - } - } - }, - { - "description": "Download when files entry does not exist", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000000" - }, - "options": {} - } - }, - "assert": { - "error": "FileNotFound" - } - }, - { - "description": "Download when an intermediate chunk is missing", - "arrange": { - "data": [ - { - "delete": "fs.chunks", - "deletes": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1 - }, - "limit": 1 - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsMissing" - } - }, - { - "description": "Download when final chunk is missing", - "arrange": { - "data": [ - { - "delete": "fs.chunks", - "deletes": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1 - }, - "limit": 1 - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsMissing" - } - }, - { - "description": "Download when an intermediate chunk is the wrong size", - "arrange": { - "data": [ - { - "update": "fs.chunks", - "updates": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 1 - }, - "u": { - "$set": { - "data": { - "$hex": "556677" - } - } - } - }, - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 2 - }, - "u": { - "$set": { - "data": { - "$hex": "8899aa" - } - } - } - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsWrongSize" - } - }, - { - "description": "Download when final chunk is the wrong size", - "arrange": { - "data": [ - { - "update": "fs.chunks", - "updates": [ - { - "q": { - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 2 - }, - "u": { - "$set": { - "data": { - "$hex": "99" - } - } - } - } - ] - } - ] - }, - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000005" - } - } - }, - "assert": { - "error": "ChunkIsWrongSize" - } - }, - { - "description": "Download legacy file with no name", - "act": { - "operation": "download", - "arguments": { - "id": { - "$oid": "000000000000000000000006" - }, - "options": {} - } - }, - "assert": { - "result": { - "$hex": "1122" - } - } - } - ] -} diff --git a/tests/GridFS/spec-tests/download_by_name.json b/tests/GridFS/spec-tests/download_by_name.json deleted file mode 100644 index ecc8c9e2c..000000000 --- a/tests/GridFS/spec-tests/download_by_name.json +++ /dev/null @@ -1,240 +0,0 @@ -{ - "data": { - "files": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "length": 1, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-01T00:00:00.000Z" - }, - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "abc", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "length": 1, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-02T00:00:00.000Z" - }, - "md5": "b15835f133ff2e27c7cb28117bfae8f4", - "filename": "abc", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "length": 1, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-03T00:00:00.000Z" - }, - "md5": "eccbc87e4b5ce2fe28308fd9f2a7baf3", - "filename": "abc", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "length": 1, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-04T00:00:00.000Z" - }, - "md5": "f623e75af30e62bbd73d6df5b50bb7b5", - "filename": "abc", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - }, - { - "_id": { - "$oid": "000000000000000000000005" - }, - "length": 1, - "chunkSize": 4, - "uploadDate": { - "$date": "1970-01-05T00:00:00.000Z" - }, - "md5": "4c614360da93c0a041b22e537de151eb", - "filename": "abc", - "contentType": "application/octet-stream", - "aliases": [], - "metadata": {} - } - ], - "chunks": [ - { - "_id": { - "$oid": "000000000000000000000001" - }, - "files_id": { - "$oid": "000000000000000000000001" - }, - "n": 0, - "data": { - "$hex": "11" - } - }, - { - "_id": { - "$oid": "000000000000000000000002" - }, - "files_id": { - "$oid": "000000000000000000000002" - }, - "n": 0, - "data": { - "$hex": "22" - } - }, - { - "_id": { - "$oid": "000000000000000000000003" - }, - "files_id": { - "$oid": "000000000000000000000003" - }, - "n": 0, - "data": { - "$hex": "33" - } - }, - { - "_id": { - "$oid": "000000000000000000000004" - }, - "files_id": { - "$oid": "000000000000000000000004" - }, - "n": 0, - "data": { - "$hex": "44" - } - }, - { - "_id": { - "$oid": "000000000000000000000005" - }, - "files_id": { - "$oid": "000000000000000000000005" - }, - "n": 0, - "data": { - "$hex": "55" - } - } - ] - }, - "tests": [ - { - "description": "Download_by_name when revision is 0", - "act": { - "operation": "download_by_name", - "arguments": { - "filename": "abc", - "options": { - "revision": 0 - } - } - }, - "assert": { - "result": { - "$hex": "11" - } - } - }, - { - "description": "Download_by_name when revision is 1", - "act": { - "operation": "download_by_name", - "arguments": { - "filename": "abc", - "options": { - "revision": 1 - } - } - }, - "assert": { - "result": { - "$hex": "22" - } - } - }, - { - "description": "Download_by_name when revision is -2", - "act": { - "operation": "download_by_name", - "arguments": { - "filename": "abc", - "options": { - "revision": -2 - } - } - }, - "assert": { - "result": { - "$hex": "44" - } - } - }, - { - "description": "Download_by_name when revision is -1", - "act": { - "operation": "download_by_name", - "arguments": { - "filename": "abc", - "options": { - "revision": -1 - } - } - }, - "assert": { - "result": { - "$hex": "55" - } - } - }, - { - "description": "Download_by_name when files entry does not exist", - "act": { - "operation": "download_by_name", - "arguments": { - "filename": "xyz" - } - }, - "assert": { - "error": "FileNotFound" - } - }, - { - "description": "Download_by_name when revision does not exist", - "act": { - "operation": "download_by_name", - "arguments": { - "filename": "abc", - "options": { - "revision": 999 - } - } - }, - "assert": { - "error": "RevisionNotFound" - } - } - ] -} diff --git a/tests/GridFS/spec-tests/upload.json b/tests/GridFS/spec-tests/upload.json deleted file mode 100644 index ecec0c548..000000000 --- a/tests/GridFS/spec-tests/upload.json +++ /dev/null @@ -1,466 +0,0 @@ -{ - "data": { - "files": [], - "chunks": [] - }, - "tests": [ - { - "description": "Upload when length is 0", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 0, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "d41d8cd98f00b204e9800998ecf8427e", - "filename": "filename" - } - ] - } - ] - } - }, - { - "description": "Upload when length is 1", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 3", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "112233" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 3, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "bafae3a174ab91fc70db7a6aa50f4f52", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "112233" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 4", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11223344" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 4, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "7e7c77cff5705d1f7574a25ef6662117", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11223344" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 5", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "1122334455" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 5, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "283d4fea5dded59cf837d3047328f5af", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": "*actual", - "files_id": "*result", - "n": 1, - "data": { - "$hex": "55" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 8", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "1122334455667788" - }, - "options": { - "chunkSizeBytes": 4 - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 8, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "dd254cdc958e53abaa67da9f797125f5", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11223344" - } - }, - { - "_id": "*actual", - "files_id": "*result", - "n": 1, - "data": { - "$hex": "55667788" - } - } - ] - } - ] - } - }, - { - "description": "Upload when contentType is provided", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4, - "contentType": "image/jpeg" - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "filename", - "contentType": "image/jpeg" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - }, - { - "description": "Upload when metadata is provided", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4, - "metadata": { - "x": 1 - } - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "md5": "47ed733b8d10be225eceba344d533586", - "filename": "filename", - "metadata": { - "x": 1 - } - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - }, - { - "description": "Upload when length is 0 sans MD5", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "" - }, - "options": { - "chunkSizeBytes": 4, - "disableMD5": true - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 0, - "chunkSize": 4, - "uploadDate": "*actual", - "filename": "filename" - } - ] - } - ] - } - }, - { - "description": "Upload when length is 1 sans MD5", - "act": { - "operation": "upload", - "arguments": { - "filename": "filename", - "source": { - "$hex": "11" - }, - "options": { - "chunkSizeBytes": 4, - "disableMD5": true - } - } - }, - "assert": { - "result": "&result", - "data": [ - { - "insert": "expected.files", - "documents": [ - { - "_id": "*result", - "length": 1, - "chunkSize": 4, - "uploadDate": "*actual", - "filename": "filename" - } - ] - }, - { - "insert": "expected.chunks", - "documents": [ - { - "_id": "*actual", - "files_id": "*result", - "n": 0, - "data": { - "$hex": "11" - } - } - ] - } - ] - } - } - ] -} diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index be9b86664..060b6a09c 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -471,7 +471,7 @@ private function executeForBucket(Bucket $bucket) case 'delete': return $bucket->delete($args['id']); case 'downloadByName': - return stream_get_contents($bucket->openDownloadStream( + return stream_get_contents($bucket->openDownloadStreamByName( $args['filename'], array_diff_key($args, ['filename' => 1]) )); diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index a20dffdc9..069fdf040 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -154,6 +154,19 @@ public function provideCrudTests() return $this->provideTests(__DIR__ . '/crud'); } + /** + * @dataProvider provideGridFSTests + */ + public function testGridFS(...$args) + { + $this->doTestCase(...$args); + } + + public function provideGridFSTests() + { + return $this->provideTests(__DIR__ . '/gridfs'); + } + /** * @dataProvider provideVersionedApiTests */ diff --git a/tests/UnifiedSpecTests/gridfs/delete.json b/tests/UnifiedSpecTests/gridfs/delete.json new file mode 100644 index 000000000..7a4ec27f8 --- /dev/null +++ b/tests/UnifiedSpecTests/gridfs/delete.json @@ -0,0 +1,799 @@ +{ + "description": "gridfs-delete", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ], + "tests": [ + { + "description": "delete when length is 0", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000001" + } + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when length is 0 and there is one extra empty chunk", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000002" + } + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when length is 8", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when files entry does not exist", + "operations": [ + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000000" + } + }, + "expectError": { + "isError": true + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "delete when files entry does not exist and there are orphaned chunks", + "operations": [ + { + "name": "deleteOne", + "object": "bucket0_files_collection", + "arguments": { + "filter": { + "_id": { + "$oid": "000000000000000000000004" + } + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "delete", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + }, + "expectError": { + "isError": true + } + } + ], + "outcome": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/gridfs/download.json b/tests/UnifiedSpecTests/gridfs/download.json new file mode 100644 index 000000000..48d324621 --- /dev/null +++ b/tests/UnifiedSpecTests/gridfs/download.json @@ -0,0 +1,558 @@ +{ + "description": "gridfs-download", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "d41d8cd98f00b204e9800998ecf8427e", + "filename": "length-0-with-empty-chunk", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "filename": "length-2", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "dd254cdc958e53abaa67da9f797125f5", + "filename": "length-8", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "length": 10, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "57d83cd477bfb1ccd975ab33d827a92b", + "filename": "length-10", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000006" + }, + "length": 2, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "c700ed4fdb1d27055aa3faa2c2432283", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000006" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000007" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2, + "data": { + "$binary": { + "base64": "mao=", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000008" + }, + "files_id": { + "$oid": "000000000000000000000006" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESI=", + "subType": "00" + } + } + } + ] + } + ], + "tests": [ + { + "description": "download when length is zero", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000001" + } + }, + "expectResult": { + "$$matchesHexBytes": "" + } + } + ] + }, + { + "description": "download when length is zero and there is one empty chunk", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000002" + } + }, + "expectResult": { + "$$matchesHexBytes": "" + } + } + ] + }, + { + "description": "download when there is one chunk", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000003" + } + }, + "expectResult": { + "$$matchesHexBytes": "1122" + } + } + ] + }, + { + "description": "download when there are two chunks", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000004" + } + }, + "expectResult": { + "$$matchesHexBytes": "1122334455667788" + } + } + ] + }, + { + "description": "download when there are three chunks", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectResult": { + "$$matchesHexBytes": "112233445566778899aa" + } + } + ] + }, + { + "description": "download when files entry does not exist", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000000" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when an intermediate chunk is missing", + "operations": [ + { + "name": "deleteOne", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when final chunk is missing", + "operations": [ + { + "name": "deleteOne", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when an intermediate chunk is the wrong size", + "operations": [ + { + "name": "bulkWrite", + "object": "bucket0_chunks_collection", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 1 + }, + "update": { + "$set": { + "data": { + "$binary": { + "base64": "VWZ3", + "subType": "00" + } + } + } + } + } + }, + { + "updateOne": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + }, + "update": { + "$set": { + "data": { + "$binary": { + "base64": "iJmq", + "subType": "00" + } + } + } + } + } + } + ] + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download when final chunk is the wrong size", + "operations": [ + { + "name": "updateOne", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": { + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 2 + }, + "update": { + "$set": { + "data": { + "$binary": { + "base64": "mQ==", + "subType": "00" + } + } + } + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1 + } + }, + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000005" + } + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "download legacy file with no name", + "operations": [ + { + "name": "download", + "object": "bucket0", + "arguments": { + "id": { + "$oid": "000000000000000000000006" + } + }, + "expectResult": { + "$$matchesHexBytes": "1122" + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/gridfs/downloadByName.json b/tests/UnifiedSpecTests/gridfs/downloadByName.json new file mode 100644 index 000000000..cd4466395 --- /dev/null +++ b/tests/UnifiedSpecTests/gridfs/downloadByName.json @@ -0,0 +1,330 @@ +{ + "description": "gridfs-downloadByName", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-01T00:00:00.000Z" + }, + "md5": "47ed733b8d10be225eceba344d533586", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-02T00:00:00.000Z" + }, + "md5": "b15835f133ff2e27c7cb28117bfae8f4", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-03T00:00:00.000Z" + }, + "md5": "eccbc87e4b5ce2fe28308fd9f2a7baf3", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-04T00:00:00.000Z" + }, + "md5": "f623e75af30e62bbd73d6df5b50bb7b5", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$date": "1970-01-05T00:00:00.000Z" + }, + "md5": "4c614360da93c0a041b22e537de151eb", + "filename": "abc", + "contentType": "application/octet-stream", + "aliases": [], + "metadata": {} + } + ] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [ + { + "_id": { + "$oid": "000000000000000000000001" + }, + "files_id": { + "$oid": "000000000000000000000001" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000002" + }, + "files_id": { + "$oid": "000000000000000000000002" + }, + "n": 0, + "data": { + "$binary": { + "base64": "Ig==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000003" + }, + "files_id": { + "$oid": "000000000000000000000003" + }, + "n": 0, + "data": { + "$binary": { + "base64": "Mw==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000004" + }, + "files_id": { + "$oid": "000000000000000000000004" + }, + "n": 0, + "data": { + "$binary": { + "base64": "RA==", + "subType": "00" + } + } + }, + { + "_id": { + "$oid": "000000000000000000000005" + }, + "files_id": { + "$oid": "000000000000000000000005" + }, + "n": 0, + "data": { + "$binary": { + "base64": "VQ==", + "subType": "00" + } + } + } + ] + } + ], + "tests": [ + { + "description": "downloadByName defaults to latest revision (-1)", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc" + }, + "expectResult": { + "$$matchesHexBytes": "55" + } + } + ] + }, + { + "description": "downloadByName when revision is 0", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 0 + }, + "expectResult": { + "$$matchesHexBytes": "11" + } + } + ] + }, + { + "description": "downloadByName when revision is 1", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 1 + }, + "expectResult": { + "$$matchesHexBytes": "22" + } + } + ] + }, + { + "description": "downloadByName when revision is 2", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 2 + }, + "expectResult": { + "$$matchesHexBytes": "33" + } + } + ] + }, + { + "description": "downloadByName when revision is -2", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": -2 + }, + "expectResult": { + "$$matchesHexBytes": "44" + } + } + ] + }, + { + "description": "downloadByName when revision is -1", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": -1 + }, + "expectResult": { + "$$matchesHexBytes": "55" + } + } + ] + }, + { + "description": "downloadByName when files entry does not exist", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "xyz" + }, + "expectError": { + "isError": true + } + } + ] + }, + { + "description": "downloadByName when revision does not exist", + "operations": [ + { + "name": "downloadByName", + "object": "bucket0", + "arguments": { + "filename": "abc", + "revision": 999 + }, + "expectError": { + "isError": true + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/gridfs/upload-disableMD5.json b/tests/UnifiedSpecTests/gridfs/upload-disableMD5.json new file mode 100644 index 000000000..d5a9d6f4a --- /dev/null +++ b/tests/UnifiedSpecTests/gridfs/upload-disableMD5.json @@ -0,0 +1,172 @@ +{ + "description": "gridfs-upload-disableMD5", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "upload when length is 0 sans MD5", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "" + }, + "chunkSizeBytes": 4, + "disableMD5": true + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$exists": false + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [] + } + ] + }, + { + "description": "upload when length is 1 sans MD5", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4, + "disableMD5": true + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$exists": false + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/gridfs/upload.json b/tests/UnifiedSpecTests/gridfs/upload.json new file mode 100644 index 000000000..97e18d2bc --- /dev/null +++ b/tests/UnifiedSpecTests/gridfs/upload.json @@ -0,0 +1,616 @@ +{ + "description": "gridfs-upload", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "gridfs-tests" + } + }, + { + "bucket": { + "id": "bucket0", + "database": "database0" + } + }, + { + "collection": { + "id": "bucket0_files_collection", + "database": "database0", + "collectionName": "fs.files" + } + }, + { + "collection": { + "id": "bucket0_chunks_collection", + "database": "database0", + "collectionName": "fs.chunks" + } + } + ], + "initialData": [ + { + "collectionName": "fs.files", + "databaseName": "gridfs-tests", + "documents": [] + }, + { + "collectionName": "fs.chunks", + "databaseName": "gridfs-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "upload when length is 0", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 0, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "d41d8cd98f00b204e9800998ecf8427e" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [] + } + ] + }, + { + "description": "upload when length is 1", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "47ed733b8d10be225eceba344d533586" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 3", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "112233" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 3, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "bafae3a174ab91fc70db7a6aa50f4f52" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIz", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 4", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11223344" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 4, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "7e7c77cff5705d1f7574a25ef6662117" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 5", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "1122334455" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 5, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "283d4fea5dded59cf837d3047328f5af" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {}, + "sort": { + "n": 1 + } + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VQ==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when length is 8", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "1122334455667788" + }, + "chunkSizeBytes": 4 + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 8, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "dd254cdc958e53abaa67da9f797125f5" + }, + "filename": "filename" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {}, + "sort": { + "n": 1 + } + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "ESIzRA==", + "subType": "00" + } + } + }, + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 1, + "data": { + "$binary": { + "base64": "VWZ3iA==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when contentType is provided", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4, + "contentType": "image/jpeg" + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "47ed733b8d10be225eceba344d533586" + }, + "filename": "filename", + "contentType": "image/jpeg" + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + }, + { + "description": "upload when metadata is provided", + "operations": [ + { + "name": "upload", + "object": "bucket0", + "arguments": { + "filename": "filename", + "source": { + "$$hexBytes": "11" + }, + "chunkSizeBytes": 4, + "metadata": { + "x": 1 + } + }, + "expectResult": { + "$$type": "objectId" + }, + "saveResultAsEntity": "uploadedObjectId" + }, + { + "name": "find", + "object": "bucket0_files_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "length": 1, + "chunkSize": 4, + "uploadDate": { + "$$type": "date" + }, + "md5": { + "$$unsetOrMatches": "47ed733b8d10be225eceba344d533586" + }, + "filename": "filename", + "metadata": { + "x": 1 + } + } + ] + }, + { + "name": "find", + "object": "bucket0_chunks_collection", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": { + "$$type": "objectId" + }, + "files_id": { + "$$matchesEntity": "uploadedObjectId" + }, + "n": 0, + "data": { + "$binary": { + "base64": "EQ==", + "subType": "00" + } + } + } + ] + } + ] + } + ] +} From d45f806dc3dfaad0717f4d7def6c0c866bbb7bf3 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 22 Apr 2021 11:08:55 -0400 Subject: [PATCH 031/321] PHPLIB-627: Comprehensive Atlas Tests (#806) * PHPLIB-613: Extract UnifiedTestRunner and model class from UnifiedSpecTest This will make it easier to invoke the UnifiedTestRunner from other test files or contexts. * Fix typos in exception messages and reference link * Rethrow internal PHP errors in Operation::assert() Like PHPUnit's AssertionFailedError, internal PHP errors are not expected for "expectError" assertions. This ensure that errors within the test runner implementation (e.g. calling a nonexistent method) will not be suppressed by the test runner itself. * PHPLIB-613: Loop operation * PHPLIB-613: EventCollector for storeEventsAsEntities client entity option * PHPLIB-613: Bump UnifiedTestRunner supported schema to 1.2 This change was necessary to support new syntax for Atlas testing; however, versioned API syntax from schema 1.1 is still unsupported. * Update valid-fail and valid-pass tests Synced with mongodb/specifications@966bf966e89f6080cdc8416861bf639ca88cc424 * PHPLIB-613: Allow a callable to receive the EntityMap after each test * PHPLIB-640: Workarounds for killAllSessions Disable the command for Atlas and update the list of ignored error codes. --- tests/UnifiedSpecTests/Context.php | 65 ++- tests/UnifiedSpecTests/EntityMap.php | 2 +- tests/UnifiedSpecTests/EventCollector.php | 176 +++++++ tests/UnifiedSpecTests/EventObserver.php | 6 +- tests/UnifiedSpecTests/Loop.php | 180 +++++++ tests/UnifiedSpecTests/Operation.php | 20 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 434 ++-------------- tests/UnifiedSpecTests/UnifiedTestCase.php | 110 ++++ tests/UnifiedSpecTests/UnifiedTestRunner.php | 468 ++++++++++++++++++ ...ntsAsEntities-conflict_with_client_id.json | 28 ++ ...ities-conflict_within_different_array.json | 43 ++ ...AsEntities-conflict_within_same_array.json | 36 ++ .../entity-client-storeEventsAsEntities.json | 67 +++ 13 files changed, 1240 insertions(+), 395 deletions(-) create mode 100644 tests/UnifiedSpecTests/EventCollector.php create mode 100644 tests/UnifiedSpecTests/Loop.php create mode 100644 tests/UnifiedSpecTests/UnifiedTestCase.php create mode 100644 tests/UnifiedSpecTests/UnifiedTestRunner.php create mode 100644 tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_with_client_id.json create mode 100644 tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_different_array.json create mode 100644 tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_same_array.json create mode 100644 tests/UnifiedSpecTests/valid-pass/entity-client-storeEventsAsEntities.json diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 5971688b2..cf2c27f20 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -7,6 +7,8 @@ use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Driver\ServerApi; +use MongoDB\Model\BSONArray; +use MongoDB\Tests\FunctionalTestCase; use stdClass; use function array_key_exists; use function array_map; @@ -26,6 +28,7 @@ use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertNotEmpty; use function PHPUnit\Framework\assertNotFalse; +use function PHPUnit\Framework\assertNotSame; use function PHPUnit\Framework\assertStringContainsString; use function PHPUnit\Framework\assertStringStartsWith; use function strlen; @@ -50,12 +53,18 @@ final class Context /** @var EntityMap */ private $entityMap; + /** @var EventCollector[] */ + private $eventCollectors = []; + /** @var EventObserver[] */ private $eventObserversByClient = []; /** @var Client */ private $internalClient; + /** @var boolean */ + private $inLoop = false; + /** @var string */ private $uri; @@ -146,6 +155,16 @@ public function setActiveClient(string $clientId = null) $this->activeClient = $clientId; } + public function isInLoop() : bool + { + return $this->inLoop; + } + + public function setInLoop(bool $inLoop) + { + $this->inLoop = $inLoop; + } + public function assertExpectedEventsForClients(array $expectedEventsForClients) { assertNotEmpty($expectedEventsForClients); @@ -186,6 +205,20 @@ public function getEventObserverForClient(string $id) : EventObserver return $this->eventObserversByClient[$id]; } + public function startEventCollectors() + { + foreach ($this->eventCollectors as $eventCollector) { + $eventCollector->start(); + } + } + + public function stopEventCollectors() + { + foreach ($this->eventCollectors as $eventCollector) { + $eventCollector->stop(); + } + } + /** @param string|array $readPreferenceTags */ private function convertReadPreferenceTags($readPreferenceTags) : array { @@ -208,12 +241,13 @@ static function (string $tag) : array { private function createClient(string $id, stdClass $o) { - Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents', 'serverApi']); + Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents', 'serverApi', 'storeEventsAsEntities']); $useMultipleMongoses = $o->useMultipleMongoses ?? null; $observeEvents = $o->observeEvents ?? null; $ignoreCommandMonitoringEvents = $o->ignoreCommandMonitoringEvents ?? []; $serverApi = $o->serverApi ?? null; + $storeEventsAsEntities = $o->storeEventsAsEntities ?? null; $uri = $this->uri; @@ -252,6 +286,14 @@ private function createClient(string $id, stdClass $o) $this->eventObserversByClient[$id] = new EventObserver($observeEvents, $ignoreCommandMonitoringEvents, $id, $this); } + if (isset($storeEventsAsEntities)) { + assertIsArray($storeEventsAsEntities); + + foreach ($storeEventsAsEntities as $storeEventsAsEntity) { + $this->createEntityCollector($id, $storeEventsAsEntity); + } + } + /* TODO: Remove this once PHPC-1645 is implemented. Each client needs * its own libmongoc client to facilitate txnNumber assertions. */ static $i = 0; @@ -266,7 +308,22 @@ private function createClient(string $id, stdClass $o) ); } - $this->entityMap->set($id, UnifiedSpecTest::createTestClient($uri, $uriOptions, $driverOptions)); + $this->entityMap->set($id, FunctionalTestCase::createTestClient($uri, $uriOptions, $driverOptions)); + } + + private function createEntityCollector(string $clientId, stdClass $o) + { + Util::assertHasOnlyKeys($o, ['id', 'events']); + + $eventListId = $o->id ?? null; + $events = $o->events ?? null; + + assertNotSame($eventListId, $clientId); + assertIsArray($events); + + $eventList = new BSONArray(); + $this->entityMap->set($eventListId, $eventList); + $this->eventCollectors[] = new EventCollector($eventList, $events, $clientId, $this); } private function createCollection(string $id, stdClass $o) @@ -410,7 +467,7 @@ private static function removeMultipleMongoses(string $uri) : string { assertStringStartsWith('mongodb://', $uri); - $manager = UnifiedSpecTest::createTestManager($uri); + $manager = FunctionalTestCase::createTestManager($uri); // Nothing to do if the URI does not refer to a sharded cluster if ($manager->selectServer(new ReadPreference(ReadPreference::PRIMARY))->getType() !== Server::TYPE_MONGOS) { @@ -450,7 +507,7 @@ private static function requireMultipleMongoses(string $uri) { assertStringStartsWith('mongodb://', $uri); - $manager = UnifiedSpecTest::createTestManager($uri); + $manager = FunctionalTestCase::createTestManager($uri); // Nothing to do if the URI does not refer to a sharded cluster if ($manager->selectServer(new ReadPreference(ReadPreference::PRIMARY))->getType() !== Server::TYPE_MONGOS) { diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php index f86715c96..5b983b6b1 100644 --- a/tests/UnifiedSpecTests/EntityMap.php +++ b/tests/UnifiedSpecTests/EntityMap.php @@ -78,7 +78,7 @@ public function offsetGet($id) */ public function offsetSet($id, $value) { - Assert::fail('Entities can only be set via register()'); + Assert::fail('Entities can only be set via set()'); } /** diff --git a/tests/UnifiedSpecTests/EventCollector.php b/tests/UnifiedSpecTests/EventCollector.php new file mode 100644 index 000000000..3942eb3e8 --- /dev/null +++ b/tests/UnifiedSpecTests/EventCollector.php @@ -0,0 +1,176 @@ + null, + 'PoolReadyEvent' => null, + 'PoolClearedEvent' => null, + 'PoolClosedEvent' => null, + 'ConnectionCreatedEvent' => null, + 'ConnectionReadyEvent' => null, + 'ConnectionClosedEvent' => null, + 'ConnectionCheckOutStartedEvent' => null, + 'ConnectionCheckOutFailedEvent' => null, + 'ConnectionCheckedOutEvent' => null, + 'ConnectionCheckedInEvent' => null, + 'CommandStartedEvent' => CommandStartedEvent::class, + 'CommandSucceededEvent' => CommandSucceededEvent::class, + 'CommandFailedEvent' => CommandFailedEvent::class, + ]; + + /** @var string */ + private $clientId; + + /** @var Context */ + private $context; + + /** @var array */ + private $collectEvents = []; + + /** @var BSONArray */ + private $eventList; + + public function __construct(BSONArray $eventList, array $collectEvents, string $clientId, Context $context) + { + assertNotEmpty($collectEvents); + + foreach ($collectEvents as $event) { + assertIsString($event); + assertArrayHasKey($event, self::$supportedEvents); + + /* CMAP events are "supported" only in the sense that we recognize + * them in the test format; however, PHPC does not implement + * connection pooling so these events cannot be collected. */ + if (self::$supportedEvents[$event] !== null) { + $this->collectEvents[self::$supportedEvents[$event]] = 1; + } + } + + $this->clientId = $clientId; + $this->context = $context; + $this->eventList = $eventList; + } + + /** + * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php + */ + public function commandFailed(CommandFailedEvent $event) + { + $this->handleCommandMonitoringEvent($event); + } + + /** + * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php + */ + public function commandStarted(CommandStartedEvent $event) + { + $this->handleCommandMonitoringEvent($event); + } + + /** + * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php + */ + public function commandSucceeded(CommandSucceededEvent $event) + { + $this->handleCommandMonitoringEvent($event); + } + + public function start() + { + addSubscriber($this); + } + + public function stop() + { + removeSubscriber($this); + } + + /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ + private function handleCommandMonitoringEvent($event) + { + assertIsObject($event); + + if (! $this->context->isActiveClient($this->clientId)) { + return; + } + + if (! isset($this->collectEvents[get_class($event)])) { + return; + } + + $log = [ + 'name' => self::getEventName($event), + 'observedAt' => microtime(true), + 'commandName' => $event->getCommandName(), + 'connectionId' => self::getConnectionId($event), + 'requestId' => $event->getRequestId(), + 'operationId' => $event->getOperationId(), + ]; + + /* Note: CommandStartedEvent.command and CommandSucceededEvent.reply can + * be omitted from logged events. */ + + if ($event instanceof CommandStartedEvent) { + $log['databaseName'] = $event->getDatabaseName(); + } + + if ($event instanceof CommandSucceededEvent) { + $log['duration'] = $event->getDurationMicros(); + } + + if ($event instanceof CommandFailedEvent) { + $log['failure'] = $event->getError()->getMessage(); + $log['duration'] = $event->getDurationMicros(); + } + + $this->eventList[] = $log; + } + + /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ + private static function getConnectionId($event) : string + { + $server = $event->getServer(); + + return sprintf('%s:%d', $server->getHost(), $server->getPort()); + } + + /** @param object $event */ + private static function getEventName($event) : string + { + static $eventNamesByClass = null; + + if ($eventNamesByClass === null) { + $eventNamesByClass = array_flip(array_filter(self::$supportedEvents)); + } + + return $eventNamesByClass[get_class($event)]; + } +} diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index b4c58d307..011e2cee0 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -31,7 +31,11 @@ use function PHPUnit\Framework\assertThat; use function sprintf; -class EventObserver implements CommandSubscriber +/** + * EventObserver handles "observeEvents" for client entities and assertions for + * "expectEvents" and special operations (e.g. assertSameLsidOnLastTwoCommands). + */ +final class EventObserver implements CommandSubscriber { /** @var array */ private static $defaultIgnoreCommands = [ diff --git a/tests/UnifiedSpecTests/Loop.php b/tests/UnifiedSpecTests/Loop.php new file mode 100644 index 000000000..2395034c5 --- /dev/null +++ b/tests/UnifiedSpecTests/Loop.php @@ -0,0 +1,180 @@ +operations = $operations; + $this->context = $context; + + foreach (['storeErrorsAsEntity', 'storeFailuresAsEntity', 'storeSuccessesAsEntity', 'storeIterationsAsEntity'] as $option) { + if (array_key_exists($option, $options)) { + assertIsString($options[$option]); + } + } + + $errorListEntityId = $options['storeErrorsAsEntity'] ?? ($options['storeFailuresAsEntity'] ?? null); + $failureListEntityId = $options['storeFailuresAsEntity'] ?? ($options['storeErrorsAsEntity'] ?? null); + + if (isset($errorListEntityId)) { + $this->errorList = $this->initializeListEntity($errorListEntityId); + } + + if (isset($failureListEntityId)) { + $this->failureList = $this->initializeListEntity($failureListEntityId); + } + + $this->numSuccessfulOperationsEntityId = $options['storeSuccessesAsEntity'] ?? null; + $this->numIterationsEntityId = $options['storeIterationsAsEntity'] ?? null; + } + + public function execute() + { + assertFalse($this->context->isInLoop(), 'Nested loops are unsupported'); + + $numIterations = 0; + $numSuccessfulOperations = 0; + + $callback = function () use (&$numSuccessfulOperations) { + foreach ($this->operations as $operation) { + $operation->assert(); + $numSuccessfulOperations++; + } + }; + + $this->context->setInLoop(true); + + try { + while (self::$allowIteration) { + $numIterations++; + try { + call_user_func($callback); + } catch (Throwable $e) { + /* Allow internal PHP errors and certain PHPUnit exceptions + * to interrupt the loop, as they are not expected here. */ + if ($e instanceof Error || $e instanceof IncompleteTest || $e instanceof SkippedTest || $e instanceof Warning) { + throw $e; + } + + $this->handleErrorOrFailure($e); + } + + if (self::$sleepUsecBetweenIterations > 0) { + usleep(self::$sleepUsecBetweenIterations); + } + } + } finally { + $this->context->setInLoop(false); + + $entityMap = $this->context->getEntityMap(); + + if (isset($this->numSuccessfulOperationsEntityId)) { + $entityMap->set($this->numSuccessfulOperationsEntityId, $numSuccessfulOperations); + } + + if (isset($this->numIterationsEntityId)) { + $entityMap->set($this->numIterationsEntityId, $numIterations); + } + } + } + + /** + * Allow or prohibit loop operations from starting a new iteration. + * + * This function is primarily used by the Atlas testing workload executor. + */ + public static function allowIteration(bool $allowIteration = true) + { + self::$allowIteration = $allowIteration; + } + + /** + * Set time to sleep between iterations. + * + * This can be used to limit CPU usage during workload execution. + */ + public static function setSleepUsecBetweenIterations(int $usec) + { + assertGreaterThanOrEqual(0, $usec); + + self::$sleepUsecBetweenIterations = $usec; + } + + private function handleErrorOrFailure(Throwable $e) + { + /* The constructor will either initialize both lists or leave them both + * unset. If unset, exceptions should not be logged and instead + * interrupt the loop. */ + if (! isset($this->errorList, $this->failureList)) { + throw $e; + } + + /* Failures and errors are differentiated according to the logic in + * PHPUnit\Framework\TestCase::runBare(). Other PHPUnit exceptions have + * already been excluded by logic in execute(). */ + $list = $e instanceof AssertionFailedError ? $this->failureList : $this->errorList; + + $list->append([ + 'error' => $e->getMessage(), + 'time' => microtime(true), + ]); + } + + private function initializeListEntity(string $id) : BSONArray + { + $entityMap = $this->context->getEntityMap(); + + if (! $entityMap->offsetExists($id)) { + $entityMap->set($id, new BSONArray()); + } + + assertInstanceOf(BSONArray::class, $entityMap[$id]); + + return $entityMap[$id]; + } +} diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 060b6a09c..0f93d094b 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -2,6 +2,7 @@ namespace MongoDB\Tests\UnifiedSpecTests; +use Error; use MongoDB\ChangeStream; use MongoDB\Client; use MongoDB\Collection; @@ -132,7 +133,10 @@ public function assert(bool $rethrowExceptions = false) $result = $this->execute(); $saveResultAsEntity = $this->saveResultAsEntity; } catch (Throwable $e) { - /* Note: we must be selective about what PHPUnit exceptions to pass + /* Rethrow any internal PHP errors and PHPUnit assertion failures, + * since those are never expected for "expectError". + * + * Note: we must be selective about what PHPUnit exceptions to pass * through, as PHPUnit's Warning exception must be considered for * expectError in GridFS tests (see: PHPLIB-592). * @@ -140,7 +144,7 @@ public function assert(bool $rethrowExceptions = false) * to the exception message. Alternatively, throw a new exception * and include this as the previous, since PHPUnit will render the * chain when reporting a test failure. */ - if ($e instanceof AssertionFailedError) { + if ($e instanceof Error || $e instanceof AssertionFailedError) { throw $e; } @@ -234,7 +238,7 @@ private function executeForChangeStream(ChangeStream $changeStream) return $changeStream->current(); default: - Assert::fail('Unsupported client operation: ' . $this->name); + Assert::fail('Unsupported change stream operation: ' . $this->name); } } @@ -567,6 +571,16 @@ private function executeForTestRunner() $operation = new DatabaseCommand('admin', $args['failPoint']); $operation->execute($args['session']->getServer()); break; + case 'loop': + assertIsArray($args['operations']); + + $operations = array_map(function ($o) { + assertIsObject($o); + + return new Operation($o, $this->context); + }, $args['operations']); + + return (new Loop($operations, $this->context, array_diff_key($args, ['operations' => 1])))->execute(); default: Assert::fail('Unsupported test runner operation: ' . $this->name); } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 069fdf040..27173e700 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -3,476 +3,138 @@ namespace MongoDB\Tests\UnifiedSpecTests; use Exception; -use MongoDB\Collection; -use MongoDB\Driver\Command; -use MongoDB\Driver\Exception\ServerException; -use MongoDB\Driver\ReadPreference; -use MongoDB\Driver\Server; -use MongoDB\Operation\DatabaseCommand; +use Generator; use MongoDB\Tests\FunctionalTestCase; -use stdClass; +use PHPUnit\Framework\SkippedTest; +use PHPUnit\Framework\Warning; use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; -use function file_get_contents; -use function gc_collect_cycles; use function glob; -use function MongoDB\BSON\fromJSON; -use function MongoDB\BSON\toPHP; -use function PHPUnit\Framework\assertTrue; -use function sprintf; -use function version_compare; /** - * Unified spec test runner. + * Unified test format spec tests. * - * @see https://github.com/mongodb/specifications/pull/846 + * @see https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst */ class UnifiedSpecTest extends FunctionalTestCase { use SetUpTearDownTrait; - const SERVER_ERROR_INTERRUPTED = 11601; - - const MIN_SCHEMA_VERSION = '1.0'; - const MAX_SCHEMA_VERSION = '1.2'; - - const TOPOLOGY_SINGLE = 'single'; - const TOPOLOGY_REPLICASET = 'replicaset'; - const TOPOLOGY_SHARDED = 'sharded'; - const TOPOLOGY_SHARDED_REPLICASET = 'sharded-replicaset'; - - /** @var MongoDB\Client */ - private static $internalClient; - - /** @var FailPointObserver */ - private $failPointObserver; + /** @var UnifiedTestRunner */ + private static $runner; private static function doSetUpBeforeClass() { parent::setUpBeforeClass(); - /* Provide internal client unmodified URI, since it may need to execute - * commands on multiple mongoses (e.g. killAllSessions) */ - self::$internalClient = self::createTestClient(static::getUri(true)); - self::killAllSessions(); - } - - private function doSetUp() - { - parent::setUp(); - - /* The transactions spec advises calling killAllSessions only at the - * start of the test suite and after failed tests; however, the "unpin - * after transient error within a transaction" pinning test causes the - * subsequent transaction test to block. */ - self::killAllSessions(); - - $this->failPointObserver = new FailPointObserver(); - $this->failPointObserver->start(); + /* Provide unmodified URI for internal client, since it may need to + * execute commands on multiple mongoses (e.g. killAllSessions) */ + self::$runner = new UnifiedTestRunner(static::getUri(true)); } - private function doTearDown() + /** + * @dataProvider provideChangeStreamsTests + */ + public function testChangeStreams(UnifiedTestCase $test) { - if ($this->hasFailed()) { - self::killAllSessions(); - } - - $this->failPointObserver->stop(); - $this->failPointObserver->disableFailPoints(); - - /* Manually invoking garbage collection since each test is prone to - * create cycles (perhaps due to EntityMap), which can leak and prevent - * sessions from being released back into the pool. */ - gc_collect_cycles(); - - parent::tearDown(); + self::$runner->run($test); } - private function doTestCase(stdClass $test, string $schemaVersion, array $runOnRequirements = null, array $createEntities = null, array $initialData = null) + public function provideChangeStreamsTests() { - if (! $this->isSchemaVersionSupported($schemaVersion)) { - $this->markTestIncomplete(sprintf('Test format schema version "%s" is not supported', $schemaVersion)); - } - - if (isset($runOnRequirements)) { - $this->checkRunOnRequirements($runOnRequirements); - } - - if (isset($test->skipReason)) { - $this->assertIsString($test->skipReason); - $this->markTestSkipped($test->skipReason); - } - - if (isset($test->runOnRequirements)) { - $this->assertIsArray($test->runOnRequirements); - $this->checkRunOnRequirements($test->runOnRequirements); - } - - if (isset($initialData)) { - $this->prepareInitialData($initialData); - } - - // Give Context unmodified URI so it can enforce useMultipleMongoses - $context = new Context(self::$internalClient, static::getUri(true)); - - if (isset($createEntities)) { - $context->createEntities($createEntities); - } - - $this->assertIsArray($test->operations); - $this->preventStaleDbVersionError($test->operations, $context); - - $context->startEventObservers(); - - foreach ($test->operations as $o) { - $operation = new Operation($o, $context); - $operation->assert(); - } - - $context->stopEventObservers(); - - if (isset($test->expectEvents)) { - $this->assertIsArray($test->expectEvents); - $context->assertExpectedEventsForClients($test->expectEvents); - } - - if (isset($test->outcome)) { - $this->assertIsArray($test->outcome); - $this->assertOutcome($test->outcome); - } + return $this->provideTests(__DIR__ . '/change-streams/*.json'); } /** * @dataProvider provideCrudTests */ - public function testCrud(...$args) + public function testCrud(UnifiedTestCase $test) { - $this->doTestCase(...$args); + self::$runner->run($test); } public function provideCrudTests() { - return $this->provideTests(__DIR__ . '/crud'); + return $this->provideTests(__DIR__ . '/crud/*.json'); } /** * @dataProvider provideGridFSTests */ - public function testGridFS(...$args) + public function testGridFS(UnifiedTestCase $test) { - $this->doTestCase(...$args); + self::$runner->run($test); } public function provideGridFSTests() { - return $this->provideTests(__DIR__ . '/gridfs'); + return $this->provideTests(__DIR__ . '/gridfs/*.json'); } /** * @dataProvider provideVersionedApiTests */ - public function testVersionedApi(...$args) + public function testVersionedApi(UnifiedTestCase $test) { - $this->doTestCase(...$args); + self::$runner->run($test); } public function provideVersionedApiTests() { - return $this->provideTests(__DIR__ . '/versioned-api'); + return $this->provideTests(__DIR__ . '/versioned-api/*.json'); } /** * @dataProvider providePassingTests */ - public function testPassingTests(...$args) + public function testPassingTests(UnifiedTestCase $test) { - $this->doTestCase(...$args); + self::$runner->run($test); } public function providePassingTests() { - return $this->provideTests(__DIR__ . '/valid-pass'); + yield from $this->provideTests(__DIR__ . '/valid-pass/*.json'); } /** * @dataProvider provideFailingTests */ - public function testFailingTests(...$args) + public function testFailingTests(UnifiedTestCase $test) { // Cannot use expectException(), as it ignores PHPUnit Exceptions $failed = false; // phpcs:disable SlevomatCodingStandard.Exceptions.ReferenceThrowableOnly.ReferencedGeneralException + /* Failing tests should never produce PHP errors, so intentionally catch + * Exception instead of Throwable. */ try { - $this->doTestCase(...$args); + self::$runner->run($test); } catch (Exception $e) { - $failed = true; + /* As is done in PHPUnit\Framework\TestCase::runBare(), exceptions + * other than a select few will indicate a test failure. We cannot + * call TestCase::hasFailed() because runBare() has yet to catch the + * exceptions and update the TestCase's status. + * + * IncompleteTest is intentionally omitted as it is thrown for an + * incompatible schema. This differs from PHPUnit's internal logic. + */ + $failed = ! ($e instanceof SkippedTest || $e instanceof Warning); } // phpcs:enable - assertTrue($failed, 'Expected test to throw an exception'); + $this->assertTrue($failed, 'Expected test to throw an exception'); } public function provideFailingTests() { - return $this->provideTests(__DIR__ . '/valid-fail'); - } - - /** - * @dataProvider provideChangeStreamsTests - */ - public function testChangeStreams(...$args) - { - $this->doTestCase(...$args); + yield from $this->provideTests(__DIR__ . '/valid-fail/*.json'); } - public function provideChangeStreamsTests() + private function provideTests(string $pattern) : Generator { - return $this->provideTests(__DIR__ . '/change-streams'); - } - - private function provideTests(string $dir) - { - $testArgs = []; - - foreach (glob($dir . '/*.json') as $filename) { - /* Decode the file through the driver's extended JSON parser to - * ensure proper handling of special types. */ - $json = toPHP(fromJSON(file_get_contents($filename))); - - $description = $json->description; - $schemaVersion = $json->schemaVersion; - $runOnRequirements = $json->runOnRequirements ?? null; - $createEntities = $json->createEntities ?? null; - $initialData = $json->initialData ?? null; - $tests = $json->tests; - - /* Assertions in data providers do not count towards test assertions - * but failures will interrupt the test suite with a warning. */ - $message = 'Invalid test file: ' . $filename; - $this->assertIsString($description, $message); - $this->assertIsString($schemaVersion, $message); - $this->assertIsArray($tests, $message); - - foreach ($json->tests as $test) { - $this->assertIsObject($test, $message); - $this->assertIsString($test->description, $message); - - $name = $description . ': ' . $test->description; - $testArgs[$name] = [$test, $schemaVersion, $runOnRequirements, $createEntities, $initialData]; - } - } - - return $testArgs; - } - - /** - * Checks server version and topology requirements. - * - * @param array $runOnRequirements - * @throws SkippedTest unless one or more runOnRequirements are met - */ - private function checkRunOnRequirements(array $runOnRequirements) - { - $this->assertNotEmpty($runOnRequirements); - $this->assertContainsOnly('object', $runOnRequirements); - - $serverVersion = $this->getCachedServerVersion(); - $topology = $this->getCachedTopology(); - $serverParameters = $this->getCachedServerParameters(); - - foreach ($runOnRequirements as $o) { - $runOnRequirement = new RunOnRequirement($o); - if ($runOnRequirement->isSatisfied($serverVersion, $topology, $serverParameters)) { - return; - } - } - - // @todo Add server parameter requirements? - $this->markTestSkipped(sprintf('Server version "%s" and topology "%s" do not meet test requirements', $serverVersion, $topology)); - } - - /** - * Return the server parameters (cached for subsequent calls). - */ - private function getCachedServerParameters() - { - static $cachedServerParameters; - - if (isset($cachedServerParameters)) { - return $cachedServerParameters; - } - - $cachedServerParameters = $this->getServerParameters(); - - return $cachedServerParameters; - } - - /** - * Return the server version (cached for subsequent calls). - * - * @return string - */ - private function getCachedServerVersion() - { - static $cachedServerVersion; - - if (isset($cachedServerVersion)) { - return $cachedServerVersion; - } - - $cachedServerVersion = $this->getServerVersion(); - - return $cachedServerVersion; - } - - /** - * Return the topology type (cached for subsequent calls). - * - * @return string - * @throws UnexpectedValueException if topology is neither single nor RS nor sharded - */ - private function getCachedTopology() - { - static $cachedTopology = null; - - if (isset($cachedTopology)) { - return $cachedTopology; - } - - switch ($this->getPrimaryServer()->getType()) { - case Server::TYPE_STANDALONE: - $cachedTopology = RunOnRequirement::TOPOLOGY_SINGLE; - break; - - case Server::TYPE_RS_PRIMARY: - $cachedTopology = RunOnRequirement::TOPOLOGY_REPLICASET; - break; - - case Server::TYPE_MONGOS: - $cachedTopology = $this->isShardedClusterUsingReplicasets() - ? RunOnRequirement::TOPOLOGY_SHARDED_REPLICASET - : RunOnRequirement::TOPOLOGY_SHARDED; - break; - - default: - throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); - } - - return $cachedTopology; - } - - private function getServerParameters() - { - $cursor = $this->manager->executeCommand( - 'admin', - new Command(['getParameter' => '*']), - new ReadPreference(ReadPreference::RP_PRIMARY) - ); - - $cursor->rewind(); - - return $cursor->current(); - } - - /** - * Checks is a test format schema version is supported. - * - * @param string $schemaVersion - * @return boolean - */ - private function isSchemaVersionSupported($schemaVersion) - { - return version_compare($schemaVersion, self::MIN_SCHEMA_VERSION, '>=') && version_compare($schemaVersion, self::MAX_SCHEMA_VERSION, '<'); - } - - /** - * Kill all sessions on the cluster. - * - * This will clean up any open transactions that may remain from a - * previously failed test. For sharded clusters, this command will be run - * on all mongos nodes. - */ - private static function killAllSessions() - { - $manager = self::$internalClient->getManager(); - $primary = $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY)); - $servers = $primary->getType() === Server::TYPE_MONGOS ? $manager->getServers() : [$primary]; - - foreach ($servers as $server) { - try { - // Skip servers that do not support sessions - if (! isset($server->getInfo()['logicalSessionTimeoutMinutes'])) { - continue; - } - - $command = new DatabaseCommand('admin', ['killAllSessions' => []]); - $command->execute($server); - } catch (ServerException $e) { - // Interrupted error is safe to ignore (see: SERVER-38335) - if ($e->getCode() != self::SERVER_ERROR_INTERRUPTED) { - throw $e; - } - } - } - } - - private function assertOutcome(array $outcome) - { - $this->assertNotEmpty($outcome); - $this->assertContainsOnly('object', $outcome); - - foreach ($outcome as $data) { - $collectionData = new CollectionData($data); - $collectionData->assertOutcome(self::$internalClient); - } - } - - private function prepareInitialData(array $initialData) - { - $this->assertNotEmpty($initialData); - $this->assertContainsOnly('object', $initialData); - - foreach ($initialData as $data) { - $collectionData = new CollectionData($data); - $collectionData->prepareInitialData(self::$internalClient); - } - } - - /** - * Work around potential error executing distinct on sharded clusters. - * - * @see https://github.com/mongodb/specifications/tree/master/source/transactions/tests#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversionts. - */ - private function preventStaleDbVersionError(array $operations, Context $context) - { - if (! $this->isShardedCluster()) { - return; - } - - $hasStartTransaction = false; - $hasDistinct = false; - $collection = null; - - foreach ($operations as $operation) { - switch ($operation->name) { - case 'distinct': - $hasDistinct = true; - $collection = $context->getEntityMap()[$operation->object]; - break; - - case 'startTransaction': - $hasStartTransaction = true; - break; - - default: - continue 2; - } - - if ($hasStartTransaction && $hasDistinct) { - $this->assertInstanceOf(Collection::class, $collection); - $collection->distinct('foo'); - - return; + foreach (glob($pattern) as $filename) { + foreach (UnifiedTestCase::fromFile($filename) as $name => $test) { + yield $name => [$test]; } } } diff --git a/tests/UnifiedSpecTests/UnifiedTestCase.php b/tests/UnifiedSpecTests/UnifiedTestCase.php new file mode 100644 index 000000000..725194e38 --- /dev/null +++ b/tests/UnifiedSpecTests/UnifiedTestCase.php @@ -0,0 +1,110 @@ +test = $test; + $this->schemaVersion = $schemaVersion; + $this->runOnRequirements = $runOnRequirements; + $this->createEntities = $createEntities; + $this->initialData = $initialData; + } + + /** + * Return this object as arguments for UnifiedTestRunner::doTestCase(). + * + * This allows the UnifiedTest object to be used directly with the argument + * unpacking operator (i.e. "..."). + * + * @see https://www.php.net/manual/en/iteratoraggregate.getiterator.php + * @see https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list + */ + public function getIterator() + { + yield $this->test; + yield $this->schemaVersion; + yield $this->runOnRequirements; + yield $this->createEntities; + yield $this->initialData; + } + + /** + * Yields UnifiedTestCase objects for a JSON file. + */ + public static function fromFile(string $filename) : Generator + { + /* Decode the file through the driver's extended JSON parser to ensure + * proper handling of special types. */ + $json = toPHP(fromJSON(file_get_contents($filename))); + + yield from static::fromJSON($json); + } + + /** + * Yields UnifiedTestCase objects for parsed JSON. + * + * The top-level and test-level "description" fields will be concatenated + * and used as the key for each yielded value. + */ + public static function fromJSON(stdClass $json) : Generator + { + $description = $json->description; + $schemaVersion = $json->schemaVersion; + $runOnRequirements = $json->runOnRequirements ?? null; + $createEntities = $json->createEntities ?? null; + $initialData = $json->initialData ?? null; + $tests = $json->tests; + + /* Assertions in data providers do not count towards test assertions + * but failures will interrupt the test suite with a warning. */ + assertIsString($description); + assertIsString($schemaVersion); + assertIsArray($tests); + + foreach ($tests as $test) { + assertIsObject($test); + assertIsString($test->description); + + $name = $description . ': ' . $test->description; + + yield $name => new self($test, $schemaVersion, $runOnRequirements, $createEntities, $initialData); + } + } +} diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php new file mode 100644 index 000000000..3f9c85f9b --- /dev/null +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -0,0 +1,468 @@ +internalClient = FunctionalTestCase::createTestClient($internalClientUri); + $this->internalClientUri = $internalClientUri; + + /* Atlas prohibits killAllSessions. Inspect the connection string to + * determine if we should avoid calling killAllSessions(). This does + * mean that lingering transactions could block test execution. */ + if (strpos($internalClientUri, self::ATLAS_TLD) !== false) { + $this->allowKillAllSessions = false; + } + } + + public function run(UnifiedTestCase $test) + { + $this->doSetUp(); + $hasFailed = false; + + try { + $this->doTestCase(...$test); + } catch (Throwable $e) { + /* As is done in PHPUnit\Framework\TestCase::runBare(), exceptions + * other than a select few will indicate a test failure. We cannot + * call TestCase::hasFailed() for two reasons: runBare() has yet to + * catch the exceptions and update the TestCase's status and, more + * importantly, this class does not have access to the TestCase. */ + $hasFailed = ! ($e instanceof IncompleteTest || $e instanceof SkippedTest || $e instanceof Warning); + + throw $e; + } finally { + /* An EntityMap observer should be invoked irrespective of the test + * succeeding or failing. Since the callable itself might throw, we + * need to ensure doTearDown() will still be called. */ + try { + if (isset($this->entityMapObserver)) { + call_user_func($this->entityMapObserver, $this->entityMap); + } + } finally { + $this->doTearDown($hasFailed); + } + } + } + + /** + * Defines a callable to receive the EntityMap after each test. + * + * This function is primarily used by the Atlas testing workload executor. + * + * @param callable(EntityMap):void $entityMapObserver + */ + public function setEntityMapObserver(callable $entityMapObserver) + { + $this->entityMapObserver = $entityMapObserver; + } + + private function doSetUp() + { + /* The transactions spec advises calling killAllSessions only at the + * start of the test suite and after failed tests; however, the "unpin + * after transient error within a transaction" pinning test causes the + * subsequent transaction test to block. */ + $this->killAllSessions(); + + $this->failPointObserver = new FailPointObserver(); + $this->failPointObserver->start(); + } + + private function doTearDown(bool $hasFailed) + { + $this->entityMap = null; + + if ($hasFailed) { + $this->killAllSessions(); + } + + $this->failPointObserver->stop(); + $this->failPointObserver->disableFailPoints(); + + /* Manually invoking garbage collection since each test is prone to + * create cycles (perhaps due to EntityMap), which can leak and prevent + * sessions from being released back into the pool. */ + gc_collect_cycles(); + } + + private function doTestCase(stdClass $test, string $schemaVersion, array $runOnRequirements = null, array $createEntities = null, array $initialData = null) + { + if (! $this->isSchemaVersionSupported($schemaVersion)) { + Assert::markTestIncomplete(sprintf('Test format schema version "%s" is not supported', $schemaVersion)); + } + + if (isset($runOnRequirements)) { + $this->checkRunOnRequirements($runOnRequirements); + } + + if (isset($test->skipReason)) { + assertIsString($test->skipReason); + Assert::markTestSkipped($test->skipReason); + } + + if (isset($test->runOnRequirements)) { + assertIsArray($test->runOnRequirements); + $this->checkRunOnRequirements($test->runOnRequirements); + } + + if (isset($initialData)) { + $this->prepareInitialData($initialData); + } + + // Give Context unmodified URI so it can enforce useMultipleMongoses + $context = new Context($this->internalClient, $this->internalClientUri); + + /* If an EntityMap observer has been configured, assign the Context's + * EntityMap to a class property so it can later be accessed from run(), + * irrespective of whether this test succeeds or fails. */ + if (isset($this->entityMapObserver)) { + $this->entityMap = $context->getEntityMap(); + } + + if (isset($createEntities)) { + $context->createEntities($createEntities); + } + + assertIsArray($test->operations); + $this->preventStaleDbVersionError($test->operations, $context); + + $context->startEventObservers(); + $context->startEventCollectors(); + + foreach ($test->operations as $o) { + $operation = new Operation($o, $context); + $operation->assert(); + } + + $context->stopEventObservers(); + $context->stopEventCollectors(); + + if (isset($test->expectEvents)) { + assertIsArray($test->expectEvents); + $context->assertExpectedEventsForClients($test->expectEvents); + } + + if (isset($test->outcome)) { + assertIsArray($test->outcome); + $this->assertOutcome($test->outcome); + } + } + + /** + * Checks server version and topology requirements. + * + * @throws SkippedTest unless one or more runOnRequirements are met + */ + private function checkRunOnRequirements(array $runOnRequirements) + { + assertNotEmpty($runOnRequirements); + assertContainsOnly('object', $runOnRequirements); + + $serverVersion = $this->getCachedServerVersion(); + $topology = $this->getCachedTopology(); + $serverParameters = $this->getCachedServerParameters(); + + foreach ($runOnRequirements as $o) { + $runOnRequirement = new RunOnRequirement($o); + if ($runOnRequirement->isSatisfied($serverVersion, $topology, $serverParameters)) { + return; + } + } + + // @todo Add server parameter requirements? + Assert::markTestSkipped(sprintf('Server version "%s" and topology "%s" do not meet test requirements', $serverVersion, $topology)); + } + + /** + * Return the server parameters (cached for subsequent calls). + */ + private function getCachedServerParameters() : stdClass + { + static $cachedServerParameters; + + if (isset($cachedServerParameters)) { + return $cachedServerParameters; + } + + $cachedServerParameters = $this->getServerParameters(); + + return $cachedServerParameters; + } + + /** + * Return the server version (cached for subsequent calls). + */ + private function getCachedServerVersion() : string + { + static $cachedServerVersion; + + if (isset($cachedServerVersion)) { + return $cachedServerVersion; + } + + $cachedServerVersion = $this->getServerVersion(); + + return $cachedServerVersion; + } + + /** + * Return the topology type (cached for subsequent calls). + * + * @throws UnexpectedValueException if topology is neither single nor RS nor sharded + */ + private function getCachedTopology() : string + { + static $cachedTopology = null; + + if (isset($cachedTopology)) { + return $cachedTopology; + } + + switch ($this->getPrimaryServer()->getType()) { + case Server::TYPE_STANDALONE: + $cachedTopology = RunOnRequirement::TOPOLOGY_SINGLE; + break; + + case Server::TYPE_RS_PRIMARY: + $cachedTopology = RunOnRequirement::TOPOLOGY_REPLICASET; + break; + + case Server::TYPE_MONGOS: + $cachedTopology = $this->isShardedClusterUsingReplicasets() + ? RunOnRequirement::TOPOLOGY_SHARDED_REPLICASET + : RunOnRequirement::TOPOLOGY_SHARDED; + break; + + default: + throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); + } + + return $cachedTopology; + } + + private function getPrimaryServer() : Server + { + $manager = $this->internalClient->getManager(); + + return $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY)); + } + + private function getServerParameters() : stdClass + { + $database = $this->internalClient->selectDatabase('admin'); + $cursor = $database->command( + ['getParameter' => '*'], + [ + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY), + 'typeMap' => [ + 'root' => 'object', + 'document' => 'object', + 'array' => 'array', + ], + ] + ); + + return $cursor->toArray()[0]; + } + + private function getServerVersion() : string + { + $database = $this->internalClient->selectDatabase('admin'); + $buildInfo = $database->command(['buildInfo' => 1])->toArray()[0]; + + if (isset($buildInfo->version) && is_string($buildInfo->version)) { + return $buildInfo->version; + } + + throw new UnexpectedValueException('Could not determine server version'); + } + + /** + * Checks is a test format schema version is supported. + */ + private function isSchemaVersionSupported(string $schemaVersion) : bool + { + return version_compare($schemaVersion, self::MIN_SCHEMA_VERSION, '>=') && version_compare($schemaVersion, self::MAX_SCHEMA_VERSION, '<='); + } + + private function isShardedClusterUsingReplicasets() : bool + { + $collection = $this->internalClient->selectCollection('config', 'shards'); + $config = $collection->findOne(); + + if ($config === null) { + return false; + } + + /** + * Use regular expression to distinguish between standalone or replicaset: + * Without a replicaset: "host" : "localhost:4100" + * With a replicaset: "host" : "dec6d8a7-9bc1-4c0e-960c-615f860b956f/localhost:4400,localhost:4401" + */ + return preg_match('@^.*/.*:\d+@', $config['host']); + } + + /** + * Kill all sessions on the cluster. + * + * This will clean up any open transactions that may remain from a + * previously failed test. For sharded clusters, this command will be run + * on all mongos nodes. + * + * This method is a NOP if allowKillAllSessions is false. + */ + private function killAllSessions() + { + static $ignoreErrorCodes = [ + self::SERVER_ERROR_INTERRUPTED, // SERVER-38335 + self::SERVER_ERROR_UNAUTHORIZED, // SERVER-54216 + ]; + + if (! $this->allowKillAllSessions) { + return; + } + + $manager = $this->internalClient->getManager(); + $primary = $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY)); + $servers = $primary->getType() === Server::TYPE_MONGOS ? $manager->getServers() : [$primary]; + + foreach ($servers as $server) { + try { + /* Skip servers that do not support sessions instead of always + * attempting the command and ignoring CommandNotFound(59) */ + if (! isset($server->getInfo()['logicalSessionTimeoutMinutes'])) { + continue; + } + + $command = new DatabaseCommand('admin', ['killAllSessions' => []]); + $command->execute($server); + } catch (ServerException $e) { + if (! in_array($e->getCode(), $ignoreErrorCodes)) { + throw $e; + } + } + } + } + + private function assertOutcome(array $outcome) + { + assertNotEmpty($outcome); + assertContainsOnly('object', $outcome); + + foreach ($outcome as $data) { + $collectionData = new CollectionData($data); + $collectionData->assertOutcome($this->internalClient); + } + } + + private function prepareInitialData(array $initialData) + { + assertNotEmpty($initialData); + assertContainsOnly('object', $initialData); + + foreach ($initialData as $data) { + $collectionData = new CollectionData($data); + $collectionData->prepareInitialData($this->internalClient); + } + } + + /** + * Work around potential error executing distinct on sharded clusters. + * + * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversion + */ + private function preventStaleDbVersionError(array $operations, Context $context) + { + if ($this->getPrimaryServer()->getType() !== Server::TYPE_MONGOS) { + return; + } + + $hasStartTransaction = false; + $hasDistinct = false; + $collection = null; + + foreach ($operations as $operation) { + switch ($operation->name) { + case 'distinct': + $hasDistinct = true; + $collection = $context->getEntityMap()[$operation->object]; + break; + + case 'startTransaction': + $hasStartTransaction = true; + break; + + default: + continue 2; + } + + if ($hasStartTransaction && $hasDistinct) { + assertInstanceOf(Collection::class, $collection); + $collection->distinct('foo'); + + return; + } + } + } +} diff --git a/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_with_client_id.json b/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_with_client_id.json new file mode 100644 index 000000000..8c0c4d204 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_with_client_id.json @@ -0,0 +1,28 @@ +{ + "description": "entity-client-storeEventsAsEntities-conflict_with_client_id", + "schemaVersion": "1.2", + "createEntities": [ + { + "client": { + "id": "client0", + "storeEventsAsEntities": [ + { + "id": "client0", + "events": [ + "PoolCreatedEvent", + "PoolReadyEvent", + "PoolClearedEvent", + "PoolClosedEvent" + ] + } + ] + } + } + ], + "tests": [ + { + "description": "foo", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_different_array.json b/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_different_array.json new file mode 100644 index 000000000..77bc4abf2 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_different_array.json @@ -0,0 +1,43 @@ +{ + "description": "entity-client-storeEventsAsEntities-conflict_within_different_array", + "schemaVersion": "1.2", + "createEntities": [ + { + "client": { + "id": "client0", + "storeEventsAsEntities": [ + { + "id": "events", + "events": [ + "PoolCreatedEvent", + "PoolReadyEvent", + "PoolClearedEvent", + "PoolClosedEvent" + ] + } + ] + } + }, + { + "client": { + "id": "client1", + "storeEventsAsEntities": [ + { + "id": "events", + "events": [ + "CommandStartedEvent", + "CommandSucceededEvent", + "CommandFailedEvent" + ] + } + ] + } + } + ], + "tests": [ + { + "description": "foo", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_same_array.json b/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_same_array.json new file mode 100644 index 000000000..e1a949988 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/entity-client-storeEventsAsEntities-conflict_within_same_array.json @@ -0,0 +1,36 @@ +{ + "description": "entity-client-storeEventsAsEntities-conflict_within_same_array", + "schemaVersion": "1.2", + "createEntities": [ + { + "client": { + "id": "client0", + "storeEventsAsEntities": [ + { + "id": "events", + "events": [ + "PoolCreatedEvent", + "PoolReadyEvent", + "PoolClearedEvent", + "PoolClosedEvent" + ] + }, + { + "id": "events", + "events": [ + "CommandStartedEvent", + "CommandSucceededEvent", + "CommandFailedEvent" + ] + } + ] + } + } + ], + "tests": [ + { + "description": "foo", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/entity-client-storeEventsAsEntities.json b/tests/UnifiedSpecTests/valid-pass/entity-client-storeEventsAsEntities.json new file mode 100644 index 000000000..e37e5a1ac --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/entity-client-storeEventsAsEntities.json @@ -0,0 +1,67 @@ +{ + "description": "entity-client-storeEventsAsEntities", + "schemaVersion": "1.2", + "createEntities": [ + { + "client": { + "id": "client0", + "storeEventsAsEntities": [ + { + "id": "client0_events", + "events": [ + "CommandStartedEvent", + "CommandSucceededEvent", + "CommandFailedEvent" + ] + } + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "test", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "storeEventsAsEntities captures events", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {} + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} From d1c5f366755bdc521e87ebb6248b32ea3aaa03a4 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 26 Apr 2021 17:32:40 -0400 Subject: [PATCH 032/321] PHPLIB-642: Sync transactions tests for unpinning after abort (#822) Synced with mongodb/specifications@ec326862be443d11f0233cee2de32a95751144df --- .evergreen/config.yml | 8 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 + .../transactions/mongos-unpin.json | 373 ++++++++++++++++++ 3 files changed, 390 insertions(+), 4 deletions(-) create mode 100644 tests/UnifiedSpecTests/transactions/mongos-unpin.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 22fdfb518..aa63d2cbc 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -463,10 +463,10 @@ axes: # * latest-stable can be updated when we start tagging 1.10 releases (even beta) # * 1.10-dev can be enabled once 1.10 has been branched # * latest-dev can be enabled once 1.10 has been branched - - id: "lowest-supported" - display_name: "1.10.0-alpha1" - variables: - EXTENSION_VERSION: "1.10.0alpha1" +# - id: "lowest-supported" +# display_name: "1.10.0-alpha1" +# variables: +# EXTENSION_VERSION: "1.10.0alpha1" - id: "latest" display_name: "1.10-dev (master)" variables: diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 27173e700..48d4482d2 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -70,6 +70,19 @@ public function provideGridFSTests() return $this->provideTests(__DIR__ . '/gridfs/*.json'); } + /** + * @dataProvider provideTransactionsTests + */ + public function testTransactions(...$args) + { + $this->doTestCase(...$args); + } + + public function provideTransactionsTests() + { + return $this->provideTests(__DIR__ . '/transactions'); + } + /** * @dataProvider provideVersionedApiTests */ diff --git a/tests/UnifiedSpecTests/transactions/mongos-unpin.json b/tests/UnifiedSpecTests/transactions/mongos-unpin.json new file mode 100644 index 000000000..33127198a --- /dev/null +++ b/tests/UnifiedSpecTests/transactions/mongos-unpin.json @@ -0,0 +1,373 @@ +{ + "description": "mongos-unpin", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "topologies": [ + "sharded-replicaset" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "mongos-unpin-db" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "mongos-unpin-db", + "documents": [] + } + ], + "_yamlAnchors": { + "anchors": 24 + }, + "tests": [ + { + "description": "unpin after TransientTransctionError error on commit", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "targetedFailPoint", + "object": "testRunner", + "arguments": { + "session": "session0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "commitTransaction", + "object": "session0", + "expectError": { + "errorCode": 24, + "errorLabelsContain": [ + "TransientTransactionError" + ], + "errorLabelsOmit": [ + "UnknownTransactionCommitResult" + ] + } + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin on successful abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin after TransientTransctionError error on abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "targetedFailPoint", + "object": "testRunner", + "arguments": { + "session": "session0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin after non-transient error on abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "targetedFailPoint", + "object": "testRunner", + "arguments": { + "session": "session0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 91 + } + } + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin when a new transaction is started", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertSessionPinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin when a non-transaction write operation uses a session", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertSessionPinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + }, + { + "description": "unpin when a non-transaction read operation uses a session", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertSessionPinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertSessionUnpinned", + "object": "testRunner", + "arguments": { + "session": "session0" + } + } + ] + } + ] +} From 95132153fb715fc2730feba7f8016ed31b0b8ba0 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 27 Apr 2021 09:28:16 +0200 Subject: [PATCH 033/321] Fix wrong transactions test calls --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 48d4482d2..d17f0c21f 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -73,14 +73,14 @@ public function provideGridFSTests() /** * @dataProvider provideTransactionsTests */ - public function testTransactions(...$args) + public function testTransactions(UnifiedTestCase $test) { - $this->doTestCase(...$args); + self::$runner->run($test); } public function provideTransactionsTests() { - return $this->provideTests(__DIR__ . '/transactions'); + return $this->provideTests(__DIR__ . '/transactions/*.json'); } /** From a9e29770ea14df2a6f49ab18fbd3c5f588ab8b23 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 27 Apr 2021 10:17:48 +0200 Subject: [PATCH 034/321] PHPLIB-645 Convert CRUD v2 spec tests to unified test format (#820) --- tests/SpecTests/CrudSpecTest.php | 155 --- tests/SpecTests/crud/aggregate-merge.json | 415 ------- .../crud/aggregate-out-readConcern.json | 385 ------ .../crud/bulkWrite-arrayFilters.json | 226 ---- .../bulkWrite-delete-hint-serverError.json | 209 ---- .../SpecTests/crud/bulkWrite-delete-hint.json | 204 ---- .../bulkWrite-update-hint-serverError.json | 343 ------ .../SpecTests/crud/bulkWrite-update-hint.json | 366 ------ .../crud/deleteMany-hint-clientError.json | 100 -- .../crud/deleteMany-hint-serverError.json | 141 --- tests/SpecTests/crud/deleteMany-hint.json | 128 -- .../crud/deleteOne-hint-clientError.json | 84 -- .../crud/deleteOne-hint-serverError.json | 121 -- tests/SpecTests/crud/deleteOne-hint.json | 116 -- .../crud/find-allowdiskuse-clientError.json | 40 - .../crud/find-allowdiskuse-serverError.json | 61 - tests/SpecTests/crud/find-allowdiskuse.json | 78 -- .../findOneAndDelete-hint-clientError.json | 84 -- .../findOneAndDelete-hint-serverError.json | 113 -- .../SpecTests/crud/findOneAndDelete-hint.json | 110 -- .../findOneAndReplace-hint-clientError.json | 90 -- .../findOneAndReplace-hint-serverError.json | 123 -- .../crud/findOneAndReplace-hint.json | 128 -- .../findOneAndUpdate-hint-clientError.json | 94 -- .../findOneAndUpdate-hint-serverError.json | 131 --- .../SpecTests/crud/findOneAndUpdate-hint.json | 136 --- tests/SpecTests/crud/replaceOne-hint.json | 146 --- .../SpecTests/crud/replaceOne-validation.json | 41 - ...ged-bulkWrite-delete-hint-clientError.json | 160 --- .../unacknowledged-bulkWrite-delete-hint.json | 174 --- ...ged-bulkWrite-update-hint-clientError.json | 250 ---- .../unacknowledged-bulkWrite-update-hint.json | 291 ----- ...nowledged-deleteMany-hint-clientError.json | 110 -- .../crud/unacknowledged-deleteMany-hint.json | 114 -- ...knowledged-deleteOne-hint-clientError.json | 94 -- .../crud/unacknowledged-deleteOne-hint.json | 102 -- ...ged-findOneAndDelete-hint-clientError.json | 94 -- .../unacknowledged-findOneAndDelete-hint.json | 94 -- ...ed-findOneAndReplace-hint-clientError.json | 100 -- ...unacknowledged-findOneAndReplace-hint.json | 101 -- ...ged-findOneAndUpdate-hint-clientError.json | 104 -- .../unacknowledged-findOneAndUpdate-hint.json | 112 -- ...nowledged-replaceOne-hint-clientError.json | 104 -- .../crud/unacknowledged-replaceOne-hint.json | 120 -- ...nowledged-updateMany-hint-clientError.json | 120 -- .../crud/unacknowledged-updateMany-hint.json | 134 --- ...knowledged-updateOne-hint-clientError.json | 108 -- .../crud/unacknowledged-updateOne-hint.json | 128 -- .../crud/updateMany-hint-serverError.json | 161 --- tests/SpecTests/crud/updateMany-hint.json | 168 --- .../SpecTests/crud/updateMany-validation.json | 57 - .../crud/updateOne-hint-clientError.json | 98 -- .../crud/updateOne-hint-serverError.json | 147 --- tests/SpecTests/crud/updateOne-hint.json | 154 --- .../SpecTests/crud/updateOne-validation.json | 39 - tests/SpecTests/crud/updateWithPipelines.json | 408 ------- .../crud/aggregate-merge.json | 497 ++++++++ .../crud/aggregate-out-readConcern.json | 406 +++++++ .../bulkWrite-arrayFilters-clientError.json | 103 +- .../crud/bulkWrite-arrayFilters.json | 275 +++++ .../bulkWrite-delete-hint-clientError.json | 119 +- .../bulkWrite-delete-hint-serverError.json | 252 ++++ .../crud/bulkWrite-delete-hint.json | 243 ++++ .../bulkWrite-update-hint-clientError.json | 151 ++- .../bulkWrite-update-hint-serverError.json | 422 +++++++ .../crud/bulkWrite-update-hint.json | 439 +++++++ .../crud/bulkWrite-update-validation.json | 121 +- .../crud/db-aggregate.json | 37 +- .../crud/deleteMany-hint-clientError.json | 149 +++ .../crud/deleteMany-hint-serverError.json | 190 +++ .../crud/deleteMany-hint.json | 173 +++ .../crud/deleteOne-hint-clientError.json | 133 +++ .../crud/deleteOne-hint-serverError.json | 170 +++ .../UnifiedSpecTests/crud/deleteOne-hint.json | 161 +++ .../crud/estimatedDocumentCount.json | 1048 ++++++++--------- .../crud/find-allowdiskuse-clientError.json | 79 ++ .../crud/find-allowdiskuse-serverError.json | 100 ++ .../crud/find-allowdiskuse.json | 120 ++ tests/UnifiedSpecTests/crud/find.json | 156 +++ .../findOneAndDelete-hint-clientError.json | 133 +++ .../findOneAndDelete-hint-serverError.json | 162 +++ .../crud/findOneAndDelete-hint.json | 155 +++ .../findOneAndReplace-hint-clientError.json | 139 +++ .../findOneAndReplace-hint-serverError.json | 172 +++ .../crud/findOneAndReplace-hint.json | 173 +++ .../findOneAndUpdate-hint-clientError.json | 143 +++ .../findOneAndUpdate-hint-serverError.json | 180 +++ .../crud/findOneAndUpdate-hint.json | 181 +++ .../crud/replaceOne-hint.json | 203 ++++ .../crud/replaceOne-validation.json | 82 ++ .../crud/updateMany-hint-clientError.json | 95 +- .../crud/updateMany-hint-serverError.json | 216 ++++ .../crud/updateMany-hint.json | 219 ++++ .../crud/updateMany-validation.json | 98 ++ .../crud/updateOne-hint-clientError.json | 147 +++ .../crud/updateOne-hint-serverError.json | 208 ++++ .../UnifiedSpecTests/crud/updateOne-hint.json | 211 ++++ .../crud/updateOne-validation.json | 80 ++ .../crud/updateWithPipelines.json | 494 ++++++++ 99 files changed, 8331 insertions(+), 8918 deletions(-) delete mode 100644 tests/SpecTests/CrudSpecTest.php delete mode 100644 tests/SpecTests/crud/aggregate-merge.json delete mode 100644 tests/SpecTests/crud/aggregate-out-readConcern.json delete mode 100644 tests/SpecTests/crud/bulkWrite-arrayFilters.json delete mode 100644 tests/SpecTests/crud/bulkWrite-delete-hint-serverError.json delete mode 100644 tests/SpecTests/crud/bulkWrite-delete-hint.json delete mode 100644 tests/SpecTests/crud/bulkWrite-update-hint-serverError.json delete mode 100644 tests/SpecTests/crud/bulkWrite-update-hint.json delete mode 100644 tests/SpecTests/crud/deleteMany-hint-clientError.json delete mode 100644 tests/SpecTests/crud/deleteMany-hint-serverError.json delete mode 100644 tests/SpecTests/crud/deleteMany-hint.json delete mode 100644 tests/SpecTests/crud/deleteOne-hint-clientError.json delete mode 100644 tests/SpecTests/crud/deleteOne-hint-serverError.json delete mode 100644 tests/SpecTests/crud/deleteOne-hint.json delete mode 100644 tests/SpecTests/crud/find-allowdiskuse-clientError.json delete mode 100644 tests/SpecTests/crud/find-allowdiskuse-serverError.json delete mode 100644 tests/SpecTests/crud/find-allowdiskuse.json delete mode 100644 tests/SpecTests/crud/findOneAndDelete-hint-clientError.json delete mode 100644 tests/SpecTests/crud/findOneAndDelete-hint-serverError.json delete mode 100644 tests/SpecTests/crud/findOneAndDelete-hint.json delete mode 100644 tests/SpecTests/crud/findOneAndReplace-hint-clientError.json delete mode 100644 tests/SpecTests/crud/findOneAndReplace-hint-serverError.json delete mode 100644 tests/SpecTests/crud/findOneAndReplace-hint.json delete mode 100644 tests/SpecTests/crud/findOneAndUpdate-hint-clientError.json delete mode 100644 tests/SpecTests/crud/findOneAndUpdate-hint-serverError.json delete mode 100644 tests/SpecTests/crud/findOneAndUpdate-hint.json delete mode 100644 tests/SpecTests/crud/replaceOne-hint.json delete mode 100644 tests/SpecTests/crud/replaceOne-validation.json delete mode 100644 tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-deleteMany-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-deleteMany-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-deleteOne-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-deleteOne-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-replaceOne-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-replaceOne-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-updateMany-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-updateMany-hint.json delete mode 100644 tests/SpecTests/crud/unacknowledged-updateOne-hint-clientError.json delete mode 100644 tests/SpecTests/crud/unacknowledged-updateOne-hint.json delete mode 100644 tests/SpecTests/crud/updateMany-hint-serverError.json delete mode 100644 tests/SpecTests/crud/updateMany-hint.json delete mode 100644 tests/SpecTests/crud/updateMany-validation.json delete mode 100644 tests/SpecTests/crud/updateOne-hint-clientError.json delete mode 100644 tests/SpecTests/crud/updateOne-hint-serverError.json delete mode 100644 tests/SpecTests/crud/updateOne-hint.json delete mode 100644 tests/SpecTests/crud/updateOne-validation.json delete mode 100644 tests/SpecTests/crud/updateWithPipelines.json create mode 100644 tests/UnifiedSpecTests/crud/aggregate-merge.json create mode 100644 tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json rename tests/{SpecTests => UnifiedSpecTests}/crud/bulkWrite-arrayFilters-clientError.json (53%) create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json rename tests/{SpecTests => UnifiedSpecTests}/crud/bulkWrite-delete-hint-clientError.json (54%) create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json rename tests/{SpecTests => UnifiedSpecTests}/crud/bulkWrite-update-hint-clientError.json (63%) create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json rename tests/{SpecTests => UnifiedSpecTests}/crud/bulkWrite-update-validation.json (54%) rename tests/{SpecTests => UnifiedSpecTests}/crud/db-aggregate.json (70%) create mode 100644 tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/deleteMany-hint.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-hint.json create mode 100644 tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/find-allowdiskuse.json create mode 100644 tests/UnifiedSpecTests/crud/find.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json create mode 100644 tests/UnifiedSpecTests/crud/replaceOne-hint.json create mode 100644 tests/UnifiedSpecTests/crud/replaceOne-validation.json rename tests/{SpecTests => UnifiedSpecTests}/crud/updateMany-hint-clientError.json (50%) create mode 100644 tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/updateMany-hint.json create mode 100644 tests/UnifiedSpecTests/crud/updateMany-validation.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-hint.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-validation.json create mode 100644 tests/UnifiedSpecTests/crud/updateWithPipelines.json diff --git a/tests/SpecTests/CrudSpecTest.php b/tests/SpecTests/CrudSpecTest.php deleted file mode 100644 index c7f38ead3..000000000 --- a/tests/SpecTests/CrudSpecTest.php +++ /dev/null @@ -1,155 +0,0 @@ - $value) { - if ($value === null) { - static::assertObjectNotHasAttribute($key, $actual); - unset($expected->{$key}); - } - } - - static::assertDocumentsMatch($expected, $actual); - } - - /** - * Execute an individual test case from the specification. - * - * @dataProvider provideTests - * @param stdClass $test Individual "tests[]" document - * @param array $runOn Top-level "runOn" array with server requirements - * @param array $data Top-level "data" array to initialize collection - * @param string $databaseName Name of database under test - * @param string $collectionName Name of collection under test - */ - public function testCrud(stdClass $test, array $runOn = null, array $data, $databaseName = null, $collectionName = null) - { - if (isset(self::$incompleteTests[$this->dataDescription()])) { - $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); - } - - if (isset($runOn)) { - $this->checkServerRequirements($runOn); - } - - if (isset($test->skipReason)) { - $this->markTestSkipped($test->skipReason); - } - - $databaseName = $databaseName ?? $this->getDatabaseName(); - $collectionName = $collectionName ?? $this->getCollectionName(); - - $context = Context::fromCrud($test, $databaseName, $collectionName); - $this->setContext($context); - - $this->dropTestAndOutcomeCollections(); - $this->insertDataFixtures($data); - - if (isset($test->failPoint)) { - $this->configureFailPoint($test->failPoint); - } - - if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromCrud((array) $test->expectations); - $commandExpectations->startMonitoring(); - } - - foreach ($test->operations as $operation) { - Operation::fromCrud($operation)->assert($this, $context); - } - - if (isset($commandExpectations)) { - $commandExpectations->stopMonitoring(); - $commandExpectations->assert($this, $context); - } - - if (isset($test->outcome->collection->data)) { - $this->assertOutcomeCollectionData($test->outcome->collection->data); - } - } - - public function provideTests() - { - $testArgs = []; - - foreach (glob(__DIR__ . '/crud/*.json') as $filename) { - $json = $this->decodeJson(file_get_contents($filename)); - $group = basename($filename, '.json'); - $runOn = $json->runOn ?? null; - $data = $json->data ?? []; - $databaseName = $json->database_name ?? null; - $collectionName = $json->collection_name ?? null; - - foreach ($json->tests as $test) { - $name = $group . ': ' . $test->description; - $testArgs[$name] = [$test, $runOn, $data, $databaseName, $collectionName]; - } - } - - return $testArgs; - } - - /** - * Prose test 1: "errInfo" is propagated - */ - public function testErrInfoIsPropagated() - { - $runOn = [(object) ['minServerVersion' => '4.0.0']]; - $this->checkServerRequirements($runOn); - - $errInfo = (object) [ - 'writeConcern' => (object) [ - 'w' => 2, - 'wtimeout' => 0, - 'provenance' => 'clientSupplied', - ], - ]; - - $this->configureFailPoint([ - 'configureFailPoint' => 'failCommand', - 'mode' => ['times' => 1], - 'data' => [ - 'failCommands' => ['insert'], - 'writeConcernError' => [ - 'code' => 100, - 'codeName' => 'UnsatisfiableWriteConcern', - 'errmsg' => 'Not enough data-bearing nodes', - 'errInfo' => $errInfo, - ], - ], - ]); - - $client = FunctionalTestCase::createTestClient(); - - try { - $client->selectCollection($this->getDatabaseName(), $this->getCollectionName())->insertOne(['fail' => 1]); - $this->fail('Expected insert command to fail'); - } catch (BulkWriteException $e) { - self::assertEquals($errInfo, $e->getWriteResult()->getWriteConcernError()->getInfo()); - } - } -} diff --git a/tests/SpecTests/crud/aggregate-merge.json b/tests/SpecTests/crud/aggregate-merge.json deleted file mode 100644 index c61736a0b..000000000 --- a/tests/SpecTests/crud/aggregate-merge.json +++ /dev/null @@ -1,415 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.1.11" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test_aggregate_merge", - "tests": [ - { - "description": "Aggregate with $merge", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_merge", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ] - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "Aggregate with $merge and batch size of 0", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ], - "batchSize": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_merge", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ], - "cursor": {} - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "Aggregate with $merge and majority readConcern", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "majority" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_merge", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ], - "readConcern": { - "level": "majority" - } - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "Aggregate with $merge and local readConcern", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "local" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_merge", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ], - "readConcern": { - "level": "local" - } - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "Aggregate with $merge and available readConcern", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "available" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_merge", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$merge": { - "into": "other_test_collection" - } - } - ], - "readConcern": { - "level": "available" - } - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/aggregate-out-readConcern.json b/tests/SpecTests/crud/aggregate-out-readConcern.json deleted file mode 100644 index c39ee0e28..000000000 --- a/tests/SpecTests/crud/aggregate-out-readConcern.json +++ /dev/null @@ -1,385 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.1.0", - "topology": [ - "replicaset", - "sharded" - ] - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test_aggregate_out_readconcern", - "tests": [ - { - "description": "readConcern majority with out stage", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "majority" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_out_readconcern", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ], - "readConcern": { - "level": "majority" - } - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "readConcern local with out stage", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "local" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_out_readconcern", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ], - "readConcern": { - "level": "local" - } - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "readConcern available with out stage", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "available" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_out_readconcern", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ], - "readConcern": { - "level": "available" - } - } - } - } - ], - "outcome": { - "collection": { - "name": "other_test_collection", - "data": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "readConcern linearizable with out stage", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "linearizable" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ] - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_out_readconcern", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ], - "readConcern": { - "level": "linearizable" - } - } - } - } - ] - }, - { - "description": "invalid readConcern with out stage", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "collectionOptions": { - "readConcern": { - "level": "!invalid123" - } - }, - "arguments": { - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ] - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test_aggregate_out_readconcern", - "pipeline": [ - { - "$sort": { - "x": 1 - } - }, - { - "$match": { - "_id": { - "$gt": 1 - } - } - }, - { - "$out": "other_test_collection" - } - ], - "readConcern": { - "level": "!invalid123" - } - } - } - } - ] - } - ] -} diff --git a/tests/SpecTests/crud/bulkWrite-arrayFilters.json b/tests/SpecTests/crud/bulkWrite-arrayFilters.json deleted file mode 100644 index 2d3ce96de..000000000 --- a/tests/SpecTests/crud/bulkWrite-arrayFilters.json +++ /dev/null @@ -1,226 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.5.6" - } - ], - "data": [ - { - "_id": 1, - "y": [ - { - "b": 3 - }, - { - "b": 1 - } - ] - }, - { - "_id": 2, - "y": [ - { - "b": 0 - }, - { - "b": 1 - } - ] - } - ], - "collection_name": "test", - "database_name": "crud-tests", - "tests": [ - { - "description": "BulkWrite updateOne with arrayFilters", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateOne", - "arguments": { - "filter": {}, - "update": { - "$set": { - "y.$[i].b": 2 - } - }, - "arrayFilters": [ - { - "i.b": 3 - } - ] - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 0, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": {}, - "u": { - "$set": { - "y.$[i].b": 2 - } - }, - "arrayFilters": [ - { - "i.b": 3 - } - ] - } - ], - "ordered": true - }, - "command_name": "update", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "y": [ - { - "b": 2 - }, - { - "b": 1 - } - ] - }, - { - "_id": 2, - "y": [ - { - "b": 0 - }, - { - "b": 1 - } - ] - } - ] - } - } - }, - { - "description": "BulkWrite updateMany with arrayFilters", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateMany", - "arguments": { - "filter": {}, - "update": { - "$set": { - "y.$[i].b": 2 - } - }, - "arrayFilters": [ - { - "i.b": 1 - } - ] - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 0, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": {}, - "u": { - "$set": { - "y.$[i].b": 2 - } - }, - "multi": true, - "arrayFilters": [ - { - "i.b": 1 - } - ] - } - ], - "ordered": true - }, - "command_name": "update", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "y": [ - { - "b": 3 - }, - { - "b": 2 - } - ] - }, - { - "_id": 2, - "y": [ - { - "b": 0 - }, - { - "b": 2 - } - ] - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/bulkWrite-delete-hint-serverError.json b/tests/SpecTests/crud/bulkWrite-delete-hint-serverError.json deleted file mode 100644 index c68973b0f..000000000 --- a/tests/SpecTests/crud/bulkWrite-delete-hint-serverError.json +++ /dev/null @@ -1,209 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.4.0", - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "BulkWrite_delete_hint", - "tests": [ - { - "description": "BulkWrite deleteOne with hints unsupported (server-side error)", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - }, - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 2 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "BulkWrite_delete_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": "_id_", - "limit": 1 - }, - { - "q": { - "_id": 2 - }, - "hint": { - "_id": 1 - }, - "limit": 1 - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "BulkWrite deleteMany with hints unsupported (server-side error)", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_" - } - }, - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "BulkWrite_delete_hint", - "deletes": [ - { - "q": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_", - "limit": 0 - }, - { - "q": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - }, - "limit": 0 - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/bulkWrite-delete-hint.json b/tests/SpecTests/crud/bulkWrite-delete-hint.json deleted file mode 100644 index ece3238fc..000000000 --- a/tests/SpecTests/crud/bulkWrite-delete-hint.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "BulkWrite_delete_hint", - "tests": [ - { - "description": "BulkWrite deleteOne with hints", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - }, - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 2 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 2, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 0, - "modifiedCount": 0, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "BulkWrite_delete_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": "_id_", - "limit": 1 - }, - { - "q": { - "_id": 2 - }, - "hint": { - "_id": 1 - }, - "limit": 1 - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "BulkWrite deleteMany with hints", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_" - } - }, - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 3, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 0, - "modifiedCount": 0, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "BulkWrite_delete_hint", - "deletes": [ - { - "q": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_", - "limit": 0 - }, - { - "q": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - }, - "limit": 0 - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/bulkWrite-update-hint-serverError.json b/tests/SpecTests/crud/bulkWrite-update-hint-serverError.json deleted file mode 100644 index e8b96fffe..000000000 --- a/tests/SpecTests/crud/bulkWrite-update-hint-serverError.json +++ /dev/null @@ -1,343 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.4.0", - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "test_bulkwrite_update_hint", - "tests": [ - { - "description": "BulkWrite updateOne with update hints unsupported (server-side error)", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_bulkwrite_update_hint", - "updates": [ - { - "q": { - "_id": 1 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - { - "q": { - "_id": 1 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "BulkWrite updateMany with update hints unsupported (server-side error)", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_bulkwrite_update_hint", - "updates": [ - { - "q": { - "_id": { - "$lt": 3 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": "_id_" - }, - { - "q": { - "_id": { - "$lt": 3 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "BulkWrite replaceOne with update hints unsupported (server-side error)", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 3 - }, - "replacement": { - "x": 333 - }, - "hint": "_id_" - } - }, - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 4 - }, - "replacement": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_bulkwrite_update_hint", - "updates": [ - { - "q": { - "_id": 3 - }, - "u": { - "x": 333 - }, - "hint": "_id_" - }, - { - "q": { - "_id": 4 - }, - "u": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/bulkWrite-update-hint.json b/tests/SpecTests/crud/bulkWrite-update-hint.json deleted file mode 100644 index 15e169f76..000000000 --- a/tests/SpecTests/crud/bulkWrite-update-hint.json +++ /dev/null @@ -1,366 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "test_bulkwrite_update_hint", - "tests": [ - { - "description": "BulkWrite updateOne with update hints", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 0, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_bulkwrite_update_hint", - "updates": [ - { - "q": { - "_id": 1 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - { - "q": { - "_id": 1 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 13 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "BulkWrite updateMany with update hints", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 0, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 4, - "modifiedCount": 4, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_bulkwrite_update_hint", - "updates": [ - { - "q": { - "_id": { - "$lt": 3 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": "_id_" - }, - { - "q": { - "_id": { - "$lt": 3 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 13 - }, - { - "_id": 2, - "x": 24 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "BulkWrite replaceOne with update hints", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 3 - }, - "replacement": { - "x": 333 - }, - "hint": "_id_" - } - }, - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 4 - }, - "replacement": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "result": { - "deletedCount": 0, - "insertedCount": 0, - "insertedIds": {}, - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0, - "upsertedIds": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_bulkwrite_update_hint", - "updates": [ - { - "q": { - "_id": 3 - }, - "u": { - "x": 333 - }, - "hint": "_id_" - }, - { - "q": { - "_id": 4 - }, - "u": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 333 - }, - { - "_id": 4, - "x": 444 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/deleteMany-hint-clientError.json b/tests/SpecTests/crud/deleteMany-hint-clientError.json deleted file mode 100644 index 3a0d02566..000000000 --- a/tests/SpecTests/crud/deleteMany-hint-clientError.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "3.3.99" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "DeleteMany_hint", - "tests": [ - { - "description": "DeleteMany with hint string unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "DeleteMany with hint document unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/deleteMany-hint-serverError.json b/tests/SpecTests/crud/deleteMany-hint-serverError.json deleted file mode 100644 index 5829e86df..000000000 --- a/tests/SpecTests/crud/deleteMany-hint-serverError.json +++ /dev/null @@ -1,141 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.4.0", - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "DeleteMany_hint", - "tests": [ - { - "description": "DeleteMany with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteMany_hint", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_", - "limit": 0 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "DeleteMany with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteMany_hint", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - }, - "limit": 0 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/deleteMany-hint.json b/tests/SpecTests/crud/deleteMany-hint.json deleted file mode 100644 index 51ee38606..000000000 --- a/tests/SpecTests/crud/deleteMany-hint.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "DeleteMany_hint", - "tests": [ - { - "description": "DeleteMany with hint string", - "operations": [ - { - "object": "collection", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_" - }, - "result": { - "deletedCount": 2 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteMany_hint", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_", - "limit": 0 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - } - ] - } - } - }, - { - "description": "DeleteMany with hint document", - "operations": [ - { - "object": "collection", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "result": { - "deletedCount": 2 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteMany_hint", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - }, - "limit": 0 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/deleteOne-hint-clientError.json b/tests/SpecTests/crud/deleteOne-hint-clientError.json deleted file mode 100644 index 97f8ec492..000000000 --- a/tests/SpecTests/crud/deleteOne-hint-clientError.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "3.3.99" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "DeleteOne_hint", - "tests": [ - { - "description": "DeleteOne with hint string unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "DeleteOne with hint document unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/deleteOne-hint-serverError.json b/tests/SpecTests/crud/deleteOne-hint-serverError.json deleted file mode 100644 index 3cf9400a8..000000000 --- a/tests/SpecTests/crud/deleteOne-hint-serverError.json +++ /dev/null @@ -1,121 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.4.0", - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "DeleteOne_hint", - "tests": [ - { - "description": "DeleteOne with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteOne_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": "_id_", - "limit": 1 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "DeleteOne with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteOne_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": { - "_id": 1 - }, - "limit": 1 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/deleteOne-hint.json b/tests/SpecTests/crud/deleteOne-hint.json deleted file mode 100644 index ec8e7715a..000000000 --- a/tests/SpecTests/crud/deleteOne-hint.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "DeleteOne_hint", - "tests": [ - { - "description": "DeleteOne with hint string", - "operations": [ - { - "object": "collection", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "result": { - "deletedCount": 1 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteOne_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": "_id_", - "limit": 1 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "deleteOne with hint document", - "operations": [ - { - "object": "collection", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "result": { - "deletedCount": 1 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteOne_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": { - "_id": 1 - }, - "limit": 1 - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/find-allowdiskuse-clientError.json b/tests/SpecTests/crud/find-allowdiskuse-clientError.json deleted file mode 100644 index 5ea013966..000000000 --- a/tests/SpecTests/crud/find-allowdiskuse-clientError.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "3.0.99" - } - ], - "collection_name": "test_find_allowdiskuse_clienterror", - "tests": [ - { - "description": "Find fails when allowDiskUse true is specified against pre 3.2 server", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {}, - "allowDiskUse": true - }, - "error": true - } - ], - "expectations": [] - }, - { - "description": "Find fails when allowDiskUse false is specified against pre 3.2 server", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {}, - "allowDiskUse": false - }, - "error": true - } - ], - "expectations": [] - } - ] -} diff --git a/tests/SpecTests/crud/find-allowdiskuse-serverError.json b/tests/SpecTests/crud/find-allowdiskuse-serverError.json deleted file mode 100644 index 31aa50e95..000000000 --- a/tests/SpecTests/crud/find-allowdiskuse-serverError.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.2", - "maxServerVersion": "4.3.0" - } - ], - "collection_name": "test_find_allowdiskuse_servererror", - "tests": [ - { - "description": "Find fails when allowDiskUse true is specified against pre 4.4 server (server-side error)", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {}, - "allowDiskUse": true - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test_find_allowdiskuse_servererror", - "filter": {}, - "allowDiskUse": true - } - } - } - ] - }, - { - "description": "Find fails when allowDiskUse false is specified against pre 4.4 server (server-side error)", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {}, - "allowDiskUse": false - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test_find_allowdiskuse_servererror", - "filter": {}, - "allowDiskUse": false - } - } - } - ] - } - ] -} diff --git a/tests/SpecTests/crud/find-allowdiskuse.json b/tests/SpecTests/crud/find-allowdiskuse.json deleted file mode 100644 index 2df4dbc98..000000000 --- a/tests/SpecTests/crud/find-allowdiskuse.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.1" - } - ], - "collection_name": "test_find_allowdiskuse", - "tests": [ - { - "description": "Find does not send allowDiskuse when value is not specified", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {} - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test_find_allowdiskuse", - "allowDiskUse": null - } - } - } - ] - }, - { - "description": "Find sends allowDiskuse false when false is specified", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {}, - "allowDiskUse": false - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test_find_allowdiskuse", - "allowDiskUse": false - } - } - } - ] - }, - { - "description": "Find sends allowDiskUse true when true is specified", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": {}, - "allowDiskUse": true - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test_find_allowdiskuse", - "allowDiskUse": true - } - } - } - ] - } - ] -} \ No newline at end of file diff --git a/tests/SpecTests/crud/findOneAndDelete-hint-clientError.json b/tests/SpecTests/crud/findOneAndDelete-hint-clientError.json deleted file mode 100644 index 262e78ce7..000000000 --- a/tests/SpecTests/crud/findOneAndDelete-hint-clientError.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.0.99" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndDelete_hint", - "tests": [ - { - "description": "FindOneAndDelete with hint string unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndDelete with hint document", - "operations": [ - { - "object": "collection", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndDelete-hint-serverError.json b/tests/SpecTests/crud/findOneAndDelete-hint-serverError.json deleted file mode 100644 index 9412b36f2..000000000 --- a/tests/SpecTests/crud/findOneAndDelete-hint-serverError.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0", - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndDelete_hint", - "tests": [ - { - "description": "FindOneAndDelete with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndDelete_hint", - "query": { - "_id": 1 - }, - "hint": "_id_", - "remove": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndDelete with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndDelete_hint", - "query": { - "_id": 1 - }, - "hint": { - "_id": 1 - }, - "remove": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndDelete-hint.json b/tests/SpecTests/crud/findOneAndDelete-hint.json deleted file mode 100644 index fe8dcfa4c..000000000 --- a/tests/SpecTests/crud/findOneAndDelete-hint.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndDelete_hint", - "tests": [ - { - "description": "FindOneAndDelete with hint string", - "operations": [ - { - "object": "collection", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "result": { - "_id": 1, - "x": 11 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndDelete_hint", - "query": { - "_id": 1 - }, - "hint": "_id_", - "remove": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndDelete with hint document", - "operations": [ - { - "object": "collection", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "result": { - "_id": 1, - "x": 11 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndDelete_hint", - "query": { - "_id": 1 - }, - "hint": { - "_id": 1 - }, - "remove": true - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndReplace-hint-clientError.json b/tests/SpecTests/crud/findOneAndReplace-hint-clientError.json deleted file mode 100644 index 08fd4b3ec..000000000 --- a/tests/SpecTests/crud/findOneAndReplace-hint-clientError.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.0.99" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndReplace_hint", - "tests": [ - { - "description": "FindOneAndReplace with hint string unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndReplace with hint document unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndReplace-hint-serverError.json b/tests/SpecTests/crud/findOneAndReplace-hint-serverError.json deleted file mode 100644 index 6710e6a70..000000000 --- a/tests/SpecTests/crud/findOneAndReplace-hint-serverError.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0", - "maxServerVersion": "4.3.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndReplace_hint", - "tests": [ - { - "description": "FindOneAndReplace with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndReplace_hint", - "query": { - "_id": 1 - }, - "update": { - "x": 33 - }, - "hint": "_id_" - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndReplace with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndReplace_hint", - "query": { - "_id": 1 - }, - "update": { - "x": 33 - }, - "hint": { - "_id": 1 - } - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndReplace-hint.json b/tests/SpecTests/crud/findOneAndReplace-hint.json deleted file mode 100644 index 263fdf962..000000000 --- a/tests/SpecTests/crud/findOneAndReplace-hint.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.1" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndReplace_hint", - "tests": [ - { - "description": "FindOneAndReplace with hint string", - "operations": [ - { - "object": "collection", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": "_id_" - }, - "result": { - "_id": 1, - "x": 11 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndReplace_hint", - "query": { - "_id": 1 - }, - "update": { - "x": 33 - }, - "hint": "_id_" - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 33 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndReplace with hint document", - "operations": [ - { - "object": "collection", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": { - "_id": 1 - } - }, - "result": { - "_id": 1, - "x": 11 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndReplace_hint", - "query": { - "_id": 1 - }, - "update": { - "x": 33 - }, - "hint": { - "_id": 1 - } - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 33 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndUpdate-hint-clientError.json b/tests/SpecTests/crud/findOneAndUpdate-hint-clientError.json deleted file mode 100644 index 8cd5cddb5..000000000 --- a/tests/SpecTests/crud/findOneAndUpdate-hint-clientError.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.0.99" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndUpdate_hint", - "tests": [ - { - "description": "FindOneAndUpdate with hint string unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndUpdate with hint document unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndUpdate-hint-serverError.json b/tests/SpecTests/crud/findOneAndUpdate-hint-serverError.json deleted file mode 100644 index 1f4b2bda8..000000000 --- a/tests/SpecTests/crud/findOneAndUpdate-hint-serverError.json +++ /dev/null @@ -1,131 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0", - "maxServerVersion": "4.3.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndUpdate_hint", - "tests": [ - { - "description": "FindOneAndUpdate with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndUpdate_hint", - "query": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndUpdate with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndUpdate_hint", - "query": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/findOneAndUpdate-hint.json b/tests/SpecTests/crud/findOneAndUpdate-hint.json deleted file mode 100644 index 451eecc01..000000000 --- a/tests/SpecTests/crud/findOneAndUpdate-hint.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.1" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndUpdate_hint", - "tests": [ - { - "description": "FindOneAndUpdate with hint string", - "operations": [ - { - "object": "collection", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "result": { - "_id": 1, - "x": 11 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndUpdate_hint", - "query": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 12 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "FindOneAndUpdate with hint document", - "operations": [ - { - "object": "collection", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "result": { - "_id": 1, - "x": 11 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndUpdate_hint", - "query": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 12 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/replaceOne-hint.json b/tests/SpecTests/crud/replaceOne-hint.json deleted file mode 100644 index de4aa4d02..000000000 --- a/tests/SpecTests/crud/replaceOne-hint.json +++ /dev/null @@ -1,146 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "test_replaceone_hint", - "tests": [ - { - "description": "ReplaceOne with hint string", - "operations": [ - { - "object": "collection", - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": "_id_" - }, - "result": { - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_replaceone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "x": 111 - }, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 111 - } - ] - } - } - }, - { - "description": "ReplaceOne with hint document", - "operations": [ - { - "object": "collection", - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": { - "_id": 1 - } - }, - "result": { - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_replaceone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "x": 111 - }, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 111 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/replaceOne-validation.json b/tests/SpecTests/crud/replaceOne-validation.json deleted file mode 100644 index 2de4a6728..000000000 --- a/tests/SpecTests/crud/replaceOne-validation.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - } - ], - "tests": [ - { - "description": "ReplaceOne prohibits atomic modifiers", - "operations": [ - { - "object": "collection", - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "$set": { - "x": 22 - } - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json deleted file mode 100644 index a92c5dfb8..000000000 --- a/tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "BulkWrite_delete_hint", - "tests": [ - { - "description": "Unacknowledged bulkWrite deleteOne with hints fails with client-side error on server < 4.4", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - }, - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 2 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "Unacknowledged bulkWrite deleteMany with hints fails with client-side error on server < 4.4", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_" - } - }, - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint.json b/tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint.json deleted file mode 100644 index b2147a27f..000000000 --- a/tests/SpecTests/crud/unacknowledged-bulkWrite-delete-hint.json +++ /dev/null @@ -1,174 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "BulkWrite_delete_hint", - "tests": [ - { - "description": "Unacknowledged bulkWrite deleteOne with hints succeeds on server >= 4.4", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - }, - { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 2 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "BulkWrite_delete_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": "_id_", - "limit": 1 - }, - { - "q": { - "_id": 2 - }, - "hint": { - "_id": 1 - }, - "limit": 1 - } - ], - "ordered": true - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged bulkWrite deleteMany with hints succeeds on server >= 4.4", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_" - } - }, - { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "BulkWrite_delete_hint", - "deletes": [ - { - "q": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_", - "limit": 0 - }, - { - "q": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - }, - "limit": 0 - } - ], - "ordered": true - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json deleted file mode 100644 index 93c46f82e..000000000 --- a/tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json +++ /dev/null @@ -1,250 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "Bulkwrite_update_hint", - "tests": [ - { - "description": "Unacknowledged bulkWrite updateOne with hints fails with client-side error on server < 4.2", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "Unacknowledged bulkWrite updateMany with hints fails with client-side error on server < 4.2", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - }, - { - "description": "Unacknowledged bulkWrite replaceOne with hints unsupported (client-side error)", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 3 - }, - "replacement": { - "x": 333 - }, - "hint": "_id_" - } - }, - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 4 - }, - "replacement": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint.json b/tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint.json deleted file mode 100644 index eaba364e9..000000000 --- a/tests/SpecTests/crud/unacknowledged-bulkWrite-update-hint.json +++ /dev/null @@ -1,291 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ], - "collection_name": "BulkWrite_update_hint", - "tests": [ - { - "description": "Unacknowledged bulkWrite updateOne with update hint succeeds on server >= 4.2", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "BulkWrite_update_hint", - "updates": [ - { - "q": { - "_id": 1 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - { - "q": { - "_id": 1 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged bulkWrite updateMany with update hint succeeds on server >= 4.2", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "BulkWrite_update_hint", - "updates": [ - { - "q": { - "_id": { - "$lt": 3 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": "_id_" - }, - { - "q": { - "_id": { - "$lt": 3 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged bulkWrite replaceOne with update hints", - "operations": [ - { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 3 - }, - "replacement": { - "x": 333 - }, - "hint": "_id_" - } - }, - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 4 - }, - "replacement": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - } - ], - "options": { - "ordered": true - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "BulkWrite_update_hint", - "updates": [ - { - "q": { - "_id": 3 - }, - "u": { - "x": 333 - }, - "hint": "_id_" - }, - { - "q": { - "_id": 4 - }, - "u": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - ], - "ordered": true - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-deleteMany-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-deleteMany-hint-clientError.json deleted file mode 100644 index 903340bf0..000000000 --- a/tests/SpecTests/crud/unacknowledged-deleteMany-hint-clientError.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "DeleteMany_hint", - "tests": [ - { - "description": "Unacknowledged deleteMany with hint string fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "Unacknowledged deleteMany with hint document fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-deleteMany-hint.json b/tests/SpecTests/crud/unacknowledged-deleteMany-hint.json deleted file mode 100644 index 485fd6198..000000000 --- a/tests/SpecTests/crud/unacknowledged-deleteMany-hint.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "DeleteMany_hint", - "tests": [ - { - "description": "Unacknowledged deleteMany with hint string succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteMany_hint", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_", - "limit": 0 - } - ] - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged deleteMany with hint document succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteMany_hint", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - }, - "limit": 0 - } - ] - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-deleteOne-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-deleteOne-hint-clientError.json deleted file mode 100644 index 11e0b883c..000000000 --- a/tests/SpecTests/crud/unacknowledged-deleteOne-hint-clientError.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "DeleteOne_hint", - "tests": [ - { - "description": "Unacknowledged deleteOne with hint string fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "Unacknowledged deleteOne with hint document fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-deleteOne-hint.json b/tests/SpecTests/crud/unacknowledged-deleteOne-hint.json deleted file mode 100644 index bd9443d4f..000000000 --- a/tests/SpecTests/crud/unacknowledged-deleteOne-hint.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "DeleteOne_hint", - "tests": [ - { - "description": "Unacknowledged deleteOne with hint string succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteOne_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": "_id_", - "limit": 1 - } - ] - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged deleteOne with hint document succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "DeleteOne_hint", - "deletes": [ - { - "q": { - "_id": 1 - }, - "hint": { - "_id": 1 - }, - "limit": 1 - } - ] - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json deleted file mode 100644 index 1c4423d3c..000000000 --- a/tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndDelete_hint", - "tests": [ - { - "description": "Unacknowledged findOneAndDelete with hint string fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "Unacknowledged findOneAndDelete with hint document fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint.json b/tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint.json deleted file mode 100644 index 9dce1ae9d..000000000 --- a/tests/SpecTests/crud/unacknowledged-findOneAndDelete-hint.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "findOneAndDelete_hint", - "tests": [ - { - "description": "Unacknowledged findOneAndDelete with hint string succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndDelete_hint", - "query": { - "_id": 1 - }, - "hint": "_id_", - "remove": true - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged findOneAndDelete with hint document succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "findOneAndDelete_hint", - "query": { - "_id": 1 - }, - "hint": { - "_id": 1 - }, - "remove": true - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json deleted file mode 100644 index 0379e7946..000000000 --- a/tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json +++ /dev/null @@ -1,100 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "FindOneAndReplace_hint", - "tests": [ - { - "description": "Unacknowledged findOneAndReplace with hint string fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "Unacknowledged findOneAndReplace with hint document fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint.json b/tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint.json deleted file mode 100644 index 7c3e55e04..000000000 --- a/tests/SpecTests/crud/unacknowledged-findOneAndReplace-hint.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "FindOneAndReplace_hint", - "tests": [ - { - "description": "Unacknowledged findOneAndReplace with hint string succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "FindOneAndReplace_hint", - "query": { - "_id": 1 - }, - "update": { - "x": 33 - }, - "hint": "_id_" - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged findOneAndReplace with hint document succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "FindOneAndReplace_hint", - "query": { - "_id": 1 - }, - "update": { - "x": 33 - } - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json deleted file mode 100644 index 14e1fb6da..000000000 --- a/tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.3.3" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "FindOneAndUpdate_hint", - "tests": [ - { - "description": "Unacknowledged findOneAndUpdate with hint string fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "Unacknowledged findOneAndUpdate with hint document fails with client-side error on server < 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint.json b/tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint.json deleted file mode 100644 index 383ca6ad6..000000000 --- a/tests/SpecTests/crud/unacknowledged-findOneAndUpdate-hint.json +++ /dev/null @@ -1,112 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.3.4" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "FindOneAndUpdate_hint", - "tests": [ - { - "description": "Unacknowledged findOneAndUpdate with hint string succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "FindOneAndUpdate_hint", - "query": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged findOneAndUpdate with hint document succeeds on server >= 4.4", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "FindOneAndUpdate_hint", - "query": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-replaceOne-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-replaceOne-hint-clientError.json deleted file mode 100644 index f442953f2..000000000 --- a/tests/SpecTests/crud/unacknowledged-replaceOne-hint-clientError.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "ReplaceOne_hint", - "tests": [ - { - "description": "Unacknowledged ReplaceOne with hint string fails with client-side error on server < 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "Unacknowledged ReplaceOne with hint document fails with client-side error on server < 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-replaceOne-hint.json b/tests/SpecTests/crud/unacknowledged-replaceOne-hint.json deleted file mode 100644 index 1d896bfb5..000000000 --- a/tests/SpecTests/crud/unacknowledged-replaceOne-hint.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "Replaceone_hint", - "tests": [ - { - "description": "Unacknowledged replaceOne with hint string succeeds on server >= 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "Replaceone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "x": 111 - }, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged replaceOne with hint document succeeds on server >= 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "Replaceone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "x": 111 - }, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-updateMany-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-updateMany-hint-clientError.json deleted file mode 100644 index 9425d542e..000000000 --- a/tests/SpecTests/crud/unacknowledged-updateMany-hint-clientError.json +++ /dev/null @@ -1,120 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "Updatemany_hint", - "tests": [ - { - "description": "Unacknowledged updateMany with hint string fails with client-side error on server < 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "Unacknowledged updateMany with hint document fails with client-side error on server < 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-updateMany-hint.json b/tests/SpecTests/crud/unacknowledged-updateMany-hint.json deleted file mode 100644 index d601a1b70..000000000 --- a/tests/SpecTests/crud/unacknowledged-updateMany-hint.json +++ /dev/null @@ -1,134 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "UpdateMany_hint", - "tests": [ - { - "description": "Unacknowledged updateMany with hint string succeeds on server >= 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "UpdateMany_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged updateMany with hint document succeeds on server >= 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "UpdateMany_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-updateOne-hint-clientError.json b/tests/SpecTests/crud/unacknowledged-updateOne-hint-clientError.json deleted file mode 100644 index bce3add67..000000000 --- a/tests/SpecTests/crud/unacknowledged-updateOne-hint-clientError.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "Updateone_hint", - "tests": [ - { - "description": "Unacknowledged updateOne with hint string fails with client-side error on server < 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "Unacknowledged updateOne with hint document fails with client-side error on server < 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": {}, - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/unacknowledged-updateOne-hint.json b/tests/SpecTests/crud/unacknowledged-updateOne-hint.json deleted file mode 100644 index ca2f57f62..000000000 --- a/tests/SpecTests/crud/unacknowledged-updateOne-hint.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "updateone_hint", - "tests": [ - { - "description": "Unacknowledged updateOne with hint string succeeds on server >= 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "updateone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": {} - }, - { - "description": "Unacknowledged updateOne with hint document succeeds on server >= 4.2", - "operations": [ - { - "object": "collection", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "updateone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": {} - } - ] -} diff --git a/tests/SpecTests/crud/updateMany-hint-serverError.json b/tests/SpecTests/crud/updateMany-hint-serverError.json deleted file mode 100644 index 86f21246e..000000000 --- a/tests/SpecTests/crud/updateMany-hint-serverError.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.4.0", - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test_updatemany_hint", - "tests": [ - { - "description": "UpdateMany with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updatemany_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - }, - { - "description": "UpdateMany with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updatemany_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateMany-hint.json b/tests/SpecTests/crud/updateMany-hint.json deleted file mode 100644 index 489348917..000000000 --- a/tests/SpecTests/crud/updateMany-hint.json +++ /dev/null @@ -1,168 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test_updatemany_hint", - "tests": [ - { - "description": "UpdateMany with hint string", - "operations": [ - { - "object": "collection", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "result": { - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updatemany_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 23 - }, - { - "_id": 3, - "x": 34 - } - ] - } - } - }, - { - "description": "UpdateMany with hint document", - "operations": [ - { - "object": "collection", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "result": { - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updatemany_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 23 - }, - { - "_id": 3, - "x": 34 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateMany-validation.json b/tests/SpecTests/crud/updateMany-validation.json deleted file mode 100644 index a85ccfa86..000000000 --- a/tests/SpecTests/crud/updateMany-validation.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "tests": [ - { - "description": "UpdateOne requires atomic modifiers", - "operations": [ - { - "object": "collection", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "x": 44 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateOne-hint-clientError.json b/tests/SpecTests/crud/updateOne-hint-clientError.json deleted file mode 100644 index 82bfe368c..000000000 --- a/tests/SpecTests/crud/updateOne-hint-clientError.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "runOn": [ - { - "maxServerVersion": "3.3.99" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "test_updateone_hint", - "tests": [ - { - "description": "UpdateOne with hint string unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "UpdateOne with hint document unsupported (client-side error)", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateOne-hint-serverError.json b/tests/SpecTests/crud/updateOne-hint-serverError.json deleted file mode 100644 index 8e8037eb8..000000000 --- a/tests/SpecTests/crud/updateOne-hint-serverError.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "3.4.0", - "maxServerVersion": "4.1.9" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "test_updateone_hint", - "tests": [ - { - "description": "UpdateOne with hint string unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updateone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - }, - { - "description": "UpdateOne with hint document unsupported (server-side error)", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updateone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateOne-hint.json b/tests/SpecTests/crud/updateOne-hint.json deleted file mode 100644 index 43f76da49..000000000 --- a/tests/SpecTests/crud/updateOne-hint.json +++ /dev/null @@ -1,154 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.2.0" - } - ], - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "collection_name": "test_updateone_hint", - "tests": [ - { - "description": "UpdateOne with hint string", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "result": { - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updateone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 23 - } - ] - } - } - }, - { - "description": "UpdateOne with hint document", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "result": { - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test_updateone_hint", - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - ] - } - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 23 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateOne-validation.json b/tests/SpecTests/crud/updateOne-validation.json deleted file mode 100644 index 6c919f5ea..000000000 --- a/tests/SpecTests/crud/updateOne-validation.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - } - ], - "tests": [ - { - "description": "UpdateOne requires atomic modifiers", - "operations": [ - { - "object": "collection", - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "x": 22 - } - }, - "error": true - } - ], - "expectations": [], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 11 - } - ] - } - } - } - ] -} diff --git a/tests/SpecTests/crud/updateWithPipelines.json b/tests/SpecTests/crud/updateWithPipelines.json deleted file mode 100644 index a310f2825..000000000 --- a/tests/SpecTests/crud/updateWithPipelines.json +++ /dev/null @@ -1,408 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.1.11" - } - ], - "data": [ - { - "_id": 1, - "x": 1, - "y": 1, - "t": { - "u": { - "v": 1 - } - } - }, - { - "_id": 2, - "x": 2, - "y": 1 - } - ], - "collection_name": "test", - "database_name": "crud-tests", - "tests": [ - { - "description": "UpdateOne using pipelines", - "operations": [ - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": [ - { - "$replaceRoot": { - "newRoot": "$t" - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - }, - "result": { - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": { - "_id": 1 - }, - "u": [ - { - "$replaceRoot": { - "newRoot": "$t" - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - } - ] - }, - "command_name": "update", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "u": { - "v": 1 - }, - "foo": 1 - }, - { - "_id": 2, - "x": 2, - "y": 1 - } - ] - } - } - }, - { - "description": "UpdateMany using pipelines", - "operations": [ - { - "name": "updateMany", - "arguments": { - "filter": {}, - "update": [ - { - "$project": { - "x": 1 - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - }, - "result": { - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": {}, - "u": [ - { - "$project": { - "x": 1 - } - }, - { - "$addFields": { - "foo": 1 - } - } - ], - "multi": true - } - ] - }, - "command_name": "update", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 1, - "foo": 1 - }, - { - "_id": 2, - "x": 2, - "foo": 1 - } - ] - } - } - }, - { - "description": "FindOneAndUpdate using pipelines", - "operations": [ - { - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": [ - { - "$project": { - "x": 1 - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "findAndModify": "test", - "update": [ - { - "$project": { - "x": 1 - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - }, - "command_name": "findAndModify", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 1, - "foo": 1 - }, - { - "_id": 2, - "x": 2, - "y": 1 - } - ] - } - } - }, - { - "description": "UpdateOne in bulk write using pipelines", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 1 - }, - "update": [ - { - "$replaceRoot": { - "newRoot": "$t" - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - } - } - ] - }, - "result": { - "matchedCount": 1, - "modifiedCount": 1, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": { - "_id": 1 - }, - "u": [ - { - "$replaceRoot": { - "newRoot": "$t" - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - } - ] - }, - "command_name": "update", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "u": { - "v": 1 - }, - "foo": 1 - }, - { - "_id": 2, - "x": 2, - "y": 1 - } - ] - } - } - }, - { - "description": "UpdateMany in bulk write using pipelines", - "operations": [ - { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "updateMany", - "arguments": { - "filter": {}, - "update": [ - { - "$project": { - "x": 1 - } - }, - { - "$addFields": { - "foo": 1 - } - } - ] - } - } - ] - }, - "result": { - "matchedCount": 2, - "modifiedCount": 2, - "upsertedCount": 0 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": {}, - "u": [ - { - "$project": { - "x": 1 - } - }, - { - "$addFields": { - "foo": 1 - } - } - ], - "multi": true - } - ] - }, - "command_name": "update", - "database_name": "crud-tests" - } - } - ], - "outcome": { - "collection": { - "data": [ - { - "_id": 1, - "x": 1, - "foo": 1 - }, - { - "_id": 2, - "x": 2, - "foo": 1 - } - ] - } - } - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/aggregate-merge.json b/tests/UnifiedSpecTests/crud/aggregate-merge.json new file mode 100644 index 000000000..c34e93a69 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate-merge.json @@ -0,0 +1,497 @@ +{ + "description": "aggregate-merge", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.1.11" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_aggregate_merge" + } + }, + { + "collection": { + "id": "collection_readConcern_majority", + "database": "database0", + "collectionName": "test_aggregate_merge", + "collectionOptions": { + "readConcern": { + "level": "majority" + } + } + } + }, + { + "collection": { + "id": "collection_readConcern_local", + "database": "database0", + "collectionName": "test_aggregate_merge", + "collectionOptions": { + "readConcern": { + "level": "local" + } + } + } + }, + { + "collection": { + "id": "collection_readConcern_available", + "database": "database0", + "collectionName": "test_aggregate_merge", + "collectionOptions": { + "readConcern": { + "level": "available" + } + } + } + } + ], + "initialData": [ + { + "collectionName": "test_aggregate_merge", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Aggregate with $merge", + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_merge", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $merge and batch size of 0", + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ], + "batchSize": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_merge", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ], + "cursor": {} + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $merge and majority readConcern", + "operations": [ + { + "object": "collection_readConcern_majority", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_merge", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ], + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $merge and local readConcern", + "operations": [ + { + "object": "collection_readConcern_local", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_merge", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ], + "readConcern": { + "level": "local" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $merge and available readConcern", + "operations": [ + { + "object": "collection_readConcern_available", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_merge", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_test_collection" + } + } + ], + "readConcern": { + "level": "available" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json b/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json new file mode 100644 index 000000000..ae1beedde --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json @@ -0,0 +1,406 @@ +{ + "description": "aggregate-out-readConcern", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.1.0", + "topologies": [ + "replicaset", + "sharded" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_aggregate_out_readconcern" + } + }, + { + "collection": { + "id": "collection_readConcern_majority", + "database": "database0", + "collectionName": "test_aggregate_out_readconcern", + "collectionOptions": { + "readConcern": { + "level": "majority" + } + } + } + }, + { + "collection": { + "id": "collection_readConcern_local", + "database": "database0", + "collectionName": "test_aggregate_out_readconcern", + "collectionOptions": { + "readConcern": { + "level": "local" + } + } + } + }, + { + "collection": { + "id": "collection_readConcern_available", + "database": "database0", + "collectionName": "test_aggregate_out_readconcern", + "collectionOptions": { + "readConcern": { + "level": "available" + } + } + } + }, + { + "collection": { + "id": "collection_readConcern_linearizable", + "database": "database0", + "collectionName": "test_aggregate_out_readconcern", + "collectionOptions": { + "readConcern": { + "level": "linearizable" + } + } + } + } + ], + "initialData": [ + { + "collectionName": "test_aggregate_out_readconcern", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "readConcern majority with out stage", + "operations": [ + { + "object": "collection_readConcern_majority", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_out_readconcern", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ], + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "readConcern local with out stage", + "operations": [ + { + "object": "collection_readConcern_local", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_out_readconcern", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ], + "readConcern": { + "level": "local" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "readConcern available with out stage", + "operations": [ + { + "object": "collection_readConcern_available", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_out_readconcern", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ], + "readConcern": { + "level": "available" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "other_test_collection", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "readConcern linearizable with out stage", + "operations": [ + { + "object": "collection_readConcern_linearizable", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ] + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test_aggregate_out_readconcern", + "pipeline": [ + { + "$sort": { + "x": 1 + } + }, + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_test_collection" + } + ], + "readConcern": { + "level": "linearizable" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/SpecTests/crud/bulkWrite-arrayFilters-clientError.json b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json similarity index 53% rename from tests/SpecTests/crud/bulkWrite-arrayFilters-clientError.json rename to tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json index 22e22f0ef..6073890dd 100644 --- a/tests/SpecTests/crud/bulkWrite-arrayFilters-clientError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json @@ -1,29 +1,61 @@ { - "runOn": [ + "description": "bulkWrite-arrayFilters-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ { "maxServerVersion": "3.5.5" } ], - "data": [ + "createEntities": [ { - "_id": 1, - "y": [ - { - "b": 3 - }, - { - "b": 1 - } - ] + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } }, { - "_id": 2, - "y": [ + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "crud-v2" + } + } + ], + "initialData": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ { - "b": 0 + "_id": 1, + "y": [ + { + "b": 3 + }, + { + "b": 1 + } + ] }, { - "b": 1 + "_id": 2, + "y": [ + { + "b": 0 + }, + { + "b": 1 + } + ] } ] } @@ -33,12 +65,12 @@ "description": "BulkWrite on server that doesn't support arrayFilters", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "updateOne", - "arguments": { + "updateOne": { "filter": {}, "update": { "$set": { @@ -53,25 +85,30 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [] + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] }, { "description": "BulkWrite on server that doesn't support arrayFilters with arrayFilters on second op", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "updateOne", - "arguments": { + "updateOne": { "filter": {}, "update": { "$set": { @@ -81,8 +118,7 @@ } }, { - "name": "updateMany", - "arguments": { + "updateMany": { "filter": {}, "update": { "$set": { @@ -97,14 +133,19 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [] + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] } ] } diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json new file mode 100644 index 000000000..8a68f51d1 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json @@ -0,0 +1,275 @@ +{ + "description": "bulkWrite-arrayFilters", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.5.6" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "y": [ + { + "b": 3 + }, + { + "b": 1 + } + ] + }, + { + "_id": 2, + "y": [ + { + "b": 0 + }, + { + "b": 1 + } + ] + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite updateOne with arrayFilters", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": {}, + "update": { + "$set": { + "y.$[i].b": 2 + } + }, + "arrayFilters": [ + { + "i.b": 3 + } + ] + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": {}, + "u": { + "$set": { + "y.$[i].b": 2 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "arrayFilters": [ + { + "i.b": 3 + } + ] + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "y": [ + { + "b": 2 + }, + { + "b": 1 + } + ] + }, + { + "_id": 2, + "y": [ + { + "b": 0 + }, + { + "b": 1 + } + ] + } + ] + } + ] + }, + { + "description": "BulkWrite updateMany with arrayFilters", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": {}, + "update": { + "$set": { + "y.$[i].b": 2 + } + }, + "arrayFilters": [ + { + "i.b": 1 + } + ] + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": {}, + "u": { + "$set": { + "y.$[i].b": 2 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "arrayFilters": [ + { + "i.b": 1 + } + ] + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "y": [ + { + "b": 3 + }, + { + "b": 2 + } + ] + }, + { + "_id": 2, + "y": [ + { + "b": 0 + }, + { + "b": 2 + } + ] + } + ] + } + ] + } + ] +} diff --git a/tests/SpecTests/crud/bulkWrite-delete-hint-clientError.json b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json similarity index 54% rename from tests/SpecTests/crud/bulkWrite-delete-hint-clientError.json rename to tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json index cfeac904c..c55067be2 100644 --- a/tests/SpecTests/crud/bulkWrite-delete-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json @@ -1,39 +1,70 @@ { - "runOn": [ + "description": "bulkWrite-delete-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ { "maxServerVersion": "3.3.99" } ], - "data": [ + "createEntities": [ { - "_id": 1, - "x": 11 + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } }, { - "_id": 2, - "x": 22 + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } }, { - "_id": 3, - "x": 33 - }, + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "BulkWrite_delete_hint" + } + } + ], + "initialData": [ { - "_id": 4, - "x": 44 + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] } ], - "collection_name": "BulkWrite_delete_hint", "tests": [ { "description": "BulkWrite deleteOne with hints unsupported (client-side error)", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "deleteOne", - "arguments": { + "deleteOne": { "filter": { "_id": 1 }, @@ -41,8 +72,7 @@ } }, { - "name": "deleteOne", - "arguments": { + "deleteOne": { "filter": { "_id": 2 }, @@ -52,17 +82,24 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -81,18 +118,18 @@ } ] } - } + ] }, { "description": "BulkWrite deleteMany with hints unsupported (client-side error)", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "deleteMany", - "arguments": { + "deleteMany": { "filter": { "_id": { "$lt": 3 @@ -102,8 +139,7 @@ } }, { - "name": "deleteMany", - "arguments": { + "deleteMany": { "filter": { "_id": { "$gte": 4 @@ -115,17 +151,24 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -144,7 +187,7 @@ } ] } - } + ] } ] } diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json new file mode 100644 index 000000000..30b9010ac --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json @@ -0,0 +1,252 @@ +{ + "description": "bulkWrite-delete-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.4.0", + "maxServerVersion": "4.3.3" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "BulkWrite_delete_hint" + } + } + ], + "initialData": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite deleteOne with hints unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + } + }, + { + "deleteOne": { + "filter": { + "_id": 2 + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_delete_hint", + "deletes": [ + { + "q": { + "_id": 1 + }, + "hint": "_id_", + "limit": 1 + }, + { + "q": { + "_id": 2 + }, + "hint": { + "_id": 1 + }, + "limit": 1 + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "BulkWrite deleteMany with hints unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "hint": "_id_" + } + }, + { + "deleteMany": { + "filter": { + "_id": { + "$gte": 4 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_delete_hint", + "deletes": [ + { + "q": { + "_id": { + "$lt": 3 + } + }, + "hint": "_id_", + "limit": 0 + }, + { + "q": { + "_id": { + "$gte": 4 + } + }, + "hint": { + "_id": 1 + }, + "limit": 0 + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json new file mode 100644 index 000000000..c892457a6 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json @@ -0,0 +1,243 @@ +{ + "description": "bulkWrite-delete-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.4" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "BulkWrite_delete_hint" + } + } + ], + "initialData": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite deleteOne with hints", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + } + }, + { + "deleteOne": { + "filter": { + "_id": 2 + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 2, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_delete_hint", + "deletes": [ + { + "q": { + "_id": 1 + }, + "hint": "_id_", + "limit": 1 + }, + { + "q": { + "_id": 2 + }, + "hint": { + "_id": 1 + }, + "limit": 1 + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "BulkWrite deleteMany with hints", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "hint": "_id_" + } + }, + { + "deleteMany": { + "filter": { + "_id": { + "$gte": 4 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 3, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_delete_hint", + "deletes": [ + { + "q": { + "_id": { + "$lt": 3 + } + }, + "hint": "_id_", + "limit": 0 + }, + { + "q": { + "_id": { + "$gte": 4 + } + }, + "hint": { + "_id": 1 + }, + "limit": 0 + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/SpecTests/crud/bulkWrite-update-hint-clientError.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json similarity index 63% rename from tests/SpecTests/crud/bulkWrite-update-hint-clientError.json rename to tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json index fa919ec51..68a92065a 100644 --- a/tests/SpecTests/crud/bulkWrite-update-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json @@ -1,39 +1,70 @@ { - "runOn": [ + "description": "bulkWrite-update-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ { "maxServerVersion": "3.3.99" } ], - "data": [ + "createEntities": [ { - "_id": 1, - "x": 11 + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } }, { - "_id": 2, - "x": 22 + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } }, { - "_id": 3, - "x": 33 - }, + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_bulkwrite_update_hint" + } + } + ], + "initialData": [ { - "_id": 4, - "x": 44 + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] } ], - "collection_name": "test_bulkwrite_update_hint", "tests": [ { "description": "BulkWrite updateOne with update hints unsupported (client-side error)", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "updateOne", - "arguments": { + "updateOne": { "filter": { "_id": 1 }, @@ -46,8 +77,7 @@ } }, { - "name": "updateOne", - "arguments": { + "updateOne": { "filter": { "_id": 1 }, @@ -62,17 +92,24 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -91,18 +128,18 @@ } ] } - } + ] }, { "description": "BulkWrite updateMany with update hints unsupported (client-side error)", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "updateMany", - "arguments": { + "updateMany": { "filter": { "_id": { "$lt": 3 @@ -117,8 +154,7 @@ } }, { - "name": "updateMany", - "arguments": { + "updateMany": { "filter": { "_id": { "$lt": 3 @@ -135,17 +171,24 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -164,18 +207,18 @@ } ] } - } + ] }, { "description": "BulkWrite replaceOne with update hints unsupported (client-side error)", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "replaceOne", - "arguments": { + "replaceOne": { "filter": { "_id": 3 }, @@ -186,8 +229,7 @@ } }, { - "name": "replaceOne", - "arguments": { + "replaceOne": { "filter": { "_id": 4 }, @@ -200,17 +242,24 @@ } } ], - "options": { - "ordered": true - } + "ordered": true }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -229,7 +278,7 @@ } ] } - } + ] } ] } diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json new file mode 100644 index 000000000..2a9a6795c --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json @@ -0,0 +1,422 @@ +{ + "description": "bulkWrite-update-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.4.0", + "maxServerVersion": "4.1.9" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_bulkwrite_update_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite updateOne with update hints unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + }, + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_bulkwrite_update_hint", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_", + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": 1 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "BulkWrite updateMany with update hints unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + }, + { + "updateMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_bulkwrite_update_hint", + "updates": [ + { + "q": { + "_id": { + "$lt": 3 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "hint": "_id_", + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$lt": 3 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "hint": { + "_id": 1 + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "BulkWrite replaceOne with update hints unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 3 + }, + "replacement": { + "x": 333 + }, + "hint": "_id_" + } + }, + { + "replaceOne": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 444 + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_bulkwrite_update_hint", + "updates": [ + { + "q": { + "_id": 3 + }, + "u": { + "x": 333 + }, + "hint": "_id_", + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": 4 + }, + "u": { + "x": 444 + }, + "hint": { + "_id": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json new file mode 100644 index 000000000..32e3787ff --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json @@ -0,0 +1,439 @@ +{ + "description": "bulkWrite-update-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_bulkwrite_update_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite updateOne with update hints", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + }, + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_bulkwrite_update_hint", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": "_id_" + }, + { + "q": { + "_id": 1 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "_id": 1 + } + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 13 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "BulkWrite updateMany with update hints", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + }, + { + "updateMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 4, + "modifiedCount": 4, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_bulkwrite_update_hint", + "updates": [ + { + "q": { + "_id": { + "$lt": 3 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": "_id_" + }, + { + "q": { + "_id": { + "$lt": 3 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "_id": 1 + } + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 13 + }, + { + "_id": 2, + "x": 24 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "BulkWrite replaceOne with update hints", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 3 + }, + "replacement": { + "x": 333 + }, + "hint": "_id_" + } + }, + { + "replaceOne": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 444 + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": {}, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_bulkwrite_update_hint", + "updates": [ + { + "q": { + "_id": 3 + }, + "u": { + "x": 333 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": "_id_" + }, + { + "q": { + "_id": 4 + }, + "u": { + "x": 444 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "_id": 1 + } + } + ], + "ordered": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 333 + }, + { + "_id": 4, + "x": 444 + } + ] + } + ] + } + ] +} diff --git a/tests/SpecTests/crud/bulkWrite-update-validation.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json similarity index 54% rename from tests/SpecTests/crud/bulkWrite-update-validation.json rename to tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json index 481e13c45..9ed7db512 100644 --- a/tests/SpecTests/crud/bulkWrite-update-validation.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json @@ -1,16 +1,48 @@ { - "data": [ + "description": "bulkWrite-update-validation", + "schemaVersion": "1.1", + "createEntities": [ { - "_id": 1, - "x": 11 + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } }, { - "_id": 2, - "x": 22 + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } }, { - "_id": 3, - "x": 33 + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "crud-v2" + } + } + ], + "initialData": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] } ], "tests": [ @@ -18,12 +50,12 @@ "description": "BulkWrite replaceOne prohibits atomic modifiers", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "replaceOne", - "arguments": { + "replaceOne": { "filter": { "_id": 1 }, @@ -36,13 +68,22 @@ } ] }, - "error": true + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "outcome": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -57,18 +98,18 @@ } ] } - } + ] }, { "description": "BulkWrite updateOne requires atomic modifiers", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "updateOne", - "arguments": { + "updateOne": { "filter": { "_id": 1 }, @@ -79,13 +120,22 @@ } ] }, - "error": true + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "outcome": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -100,18 +150,18 @@ } ] } - } + ] }, { "description": "BulkWrite updateMany requires atomic modifiers", "operations": [ { + "object": "collection0", "name": "bulkWrite", "arguments": { "requests": [ { - "name": "updateMany", - "arguments": { + "updateMany": { "filter": { "_id": { "$gt": 1 @@ -124,13 +174,22 @@ } ] }, - "error": true + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "outcome": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -145,7 +204,7 @@ } ] } - } + ] } ] } diff --git a/tests/SpecTests/crud/db-aggregate.json b/tests/UnifiedSpecTests/crud/db-aggregate.json similarity index 70% rename from tests/SpecTests/crud/db-aggregate.json rename to tests/UnifiedSpecTests/crud/db-aggregate.json index d88b9e181..6ae029175 100644 --- a/tests/SpecTests/crud/db-aggregate.json +++ b/tests/UnifiedSpecTests/crud/db-aggregate.json @@ -1,17 +1,42 @@ { - "runOn": [ + "description": "db-aggregate", + "schemaVersion": "1.1", + "runOnRequirements": [ { "minServerVersion": "3.6.0" } ], - "database_name": "admin", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "admin" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "crud-v2" + } + } + ], "tests": [ { "description": "Aggregate with $listLocalSessions", "operations": [ { + "object": "database0", "name": "aggregate", - "object": "database", "arguments": { "pipeline": [ { @@ -33,7 +58,7 @@ } ] }, - "result": [ + "expectResult": [ { "dummy": "dummy field" } @@ -45,8 +70,8 @@ "description": "Aggregate with $listLocalSessions and allowDiskUse", "operations": [ { + "object": "database0", "name": "aggregate", - "object": "database", "arguments": { "pipeline": [ { @@ -69,7 +94,7 @@ ], "allowDiskUse": true }, - "result": [ + "expectResult": [ { "dummy": "dummy field" } diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json new file mode 100644 index 000000000..285f567f0 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json @@ -0,0 +1,149 @@ +{ + "description": "deleteMany-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "3.3.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteMany_hint" + } + } + ], + "initialData": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "DeleteMany with hint string unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "DeleteMany with hint document unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json b/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json new file mode 100644 index 000000000..90bfb89fc --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json @@ -0,0 +1,190 @@ +{ + "description": "deleteMany-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.4.0", + "maxServerVersion": "4.3.3" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteMany_hint" + } + } + ], + "initialData": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "DeleteMany with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteMany_hint", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_", + "limit": 0 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "DeleteMany with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteMany_hint", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + }, + "limit": 0 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint.json b/tests/UnifiedSpecTests/crud/deleteMany-hint.json new file mode 100644 index 000000000..b0cdc0304 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint.json @@ -0,0 +1,173 @@ +{ + "description": "deleteMany-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.4" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteMany_hint" + } + } + ], + "initialData": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "DeleteMany with hint string", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteMany_hint", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_", + "limit": 0 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + }, + { + "description": "DeleteMany with hint document", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteMany_hint", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + }, + "limit": 0 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json new file mode 100644 index 000000000..b6b2932bd --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json @@ -0,0 +1,133 @@ +{ + "description": "deleteOne-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "3.3.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteOne_hint" + } + } + ], + "initialData": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "DeleteOne with hint string unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "DeleteOne with hint document unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json b/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json new file mode 100644 index 000000000..8b1398c75 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json @@ -0,0 +1,170 @@ +{ + "description": "deleteOne-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.4.0", + "maxServerVersion": "4.3.3" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteOne_hint" + } + } + ], + "initialData": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "DeleteOne with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteOne_hint", + "deletes": [ + { + "q": { + "_id": 1 + }, + "hint": "_id_", + "limit": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "DeleteOne with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteOne_hint", + "deletes": [ + { + "q": { + "_id": 1 + }, + "hint": { + "_id": 1 + }, + "limit": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint.json b/tests/UnifiedSpecTests/crud/deleteOne-hint.json new file mode 100644 index 000000000..9e3970a54 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint.json @@ -0,0 +1,161 @@ +{ + "description": "deleteOne-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.4" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteOne_hint" + } + } + ], + "initialData": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "DeleteOne with hint string", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteOne_hint", + "deletes": [ + { + "q": { + "_id": 1 + }, + "hint": "_id_", + "limit": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "deleteOne with hint document", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "DeleteOne_hint", + "deletes": [ + { + "q": { + "_id": 1 + }, + "hint": { + "_id": 1 + }, + "limit": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json b/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json index 9dc084589..bcd66ea95 100644 --- a/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json +++ b/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json @@ -1,562 +1,562 @@ { - "description": "estimatedDocumentCount", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ], - "uriOptions": { - "retryReads": false - }, - "useMultipleMongoses": false - } + "description": "estimatedDocumentCount", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "uriOptions": { + "retryReads": false }, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "edc-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "edc-tests", + "documents": [ { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "edc-tests" - } + "_id": 1, + "x": 11 }, { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "coll0" - } + "_id": 2, + "x": 22 }, { - "collection": { - "id": "collection1", - "database": "database0", - "collectionName": "coll1" - } + "_id": 3, + "x": 33 } - ], - "initialData": [ - { - "collectionName": "coll0", - "databaseName": "edc-tests", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] + ] + } + ], + "tests": [ + { + "description": "estimatedDocumentCount uses $collStats on 4.9.0 or greater", + "runOnRequirements": [ + { + "minServerVersion": "4.9.0" } - ], - "tests": [ - { - "description": "estimatedDocumentCount uses $collStats on 4.9.0 or greater", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectResult": 3 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, + ], + "operations": [ { - "description": "estimatedDocumentCount with maxTimeMS on 4.9.0 or greater", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection0", - "arguments": { - "maxTimeMS": 6000 + "name": "estimatedDocumentCount", + "object": "collection0", + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "expectResult": 3 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ], - "maxTimeMS": 6000 - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } - ] - } - ] - }, + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount with maxTimeMS on 4.9.0 or greater", + "runOnRequirements": [ { - "description": "estimatedDocumentCount on non-existent collection on 4.9.0 or greater", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection1", - "expectResult": 0 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll1", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "maxTimeMS": 6000 + }, + "expectResult": 3 + } + ], + "expectEvents": [ { - "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--command error", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], - "operations": [ - { - "name": "failPoint", - "object": "testRunner", - "arguments": { - "client": "client0", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 8 - } + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } + ], + "maxTimeMS": 6000 }, - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectError": { - "errorCode": 8 - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount on non-existent collection on 4.9.0 or greater", + "runOnRequirements": [ { - "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--socket error", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], - "operations": [ - { - "name": "failPoint", - "object": "testRunner", - "arguments": { - "client": "client0", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection1", + "expectResult": 0 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll1", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } + ] }, - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--command error", + "runOnRequirements": [ { - "description": "estimatedDocumentCount uses count on less than 4.9.0", - "runOnRequirements": [ - { - "maxServerVersion": "4.8.99" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectResult": 3 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll0" - }, - "commandName": "count", - "databaseName": "edc-tests" - } - } - ] - } - ] + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 8 + } + } + } }, { - "description": "estimatedDocumentCount with maxTimeMS on less than 4.9.0", - "runOnRequirements": [ - { - "maxServerVersion": "4.8.99" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection0", - "arguments": { - "maxTimeMS": 6000 + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "errorCode": 8 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "expectResult": 3 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll0", - "maxTimeMS": 6000 - }, - "commandName": "count", - "databaseName": "edc-tests" - } + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } - ] - } - ] - }, + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--socket error", + "runOnRequirements": [ { - "description": "estimatedDocumentCount on non-existent collection on less than 4.9.0", - "runOnRequirements": [ - { - "maxServerVersion": "4.8.99" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection1", - "expectResult": 0 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll1" - }, - "commandName": "count", - "databaseName": "edc-tests" - } - } - ] - } - ] + "minServerVersion": "4.9.0" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + } + } }, { - "description": "estimatedDocumentCount errors correctly on less than 4.9.0--command error", - "runOnRequirements": [ - { - "minServerVersion": "4.0.0", - "maxServerVersion": "4.8.99", - "topologies": [ - "single", - "replicaset" - ] - }, - { - "minServerVersion": "4.2.0", - "maxServerVersion": "4.8.99", - "topologies": [ - "sharded" - ] - } - ], - "operations": [ - { - "name": "failPoint", - "object": "testRunner", - "arguments": { - "client": "client0", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "count" - ], - "errorCode": 8 - } + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } + ] }, - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectError": { - "errorCode": 8 - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll0" - }, - "commandName": "count", - "databaseName": "edc-tests" - } - } - ] - } - ] + "commandName": "aggregate", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount uses count on less than 4.9.0", + "runOnRequirements": [ + { + "maxServerVersion": "4.8.99" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0" + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount with maxTimeMS on less than 4.9.0", + "runOnRequirements": [ + { + "maxServerVersion": "4.8.99" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "maxTimeMS": 6000 + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0", + "maxTimeMS": 6000 + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount on non-existent collection on less than 4.9.0", + "runOnRequirements": [ + { + "maxServerVersion": "4.8.99" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection1", + "expectResult": 0 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll1" + }, + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on less than 4.9.0--command error", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "count" + ], + "errorCode": 8 + } + } + } }, { - "description": "estimatedDocumentCount errors correctly on less than 4.9.0--socket error", - "runOnRequirements": [ - { - "minServerVersion": "4.0.0", - "maxServerVersion": "4.8.99", - "topologies": [ - "single", - "replicaset" - ] + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "errorCode": 8 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0" }, - { - "minServerVersion": "4.2.0", - "maxServerVersion": "4.8.99", - "topologies": [ - "sharded" - ] - } - ], - "operations": [ - { - "name": "failPoint", - "object": "testRunner", - "arguments": { - "client": "client0", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "count" - ], - "closeConnection": true - } - } - } + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount errors correctly on less than 4.9.0--socket error", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.8.99", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "count" + ], + "closeConnection": true + } + } + } + }, + { + "name": "estimatedDocumentCount", + "object": "collection0", + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0" }, - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll0" - }, - "commandName": "count", - "databaseName": "edc-tests" - } - } - ] - } - ] + "commandName": "count", + "databaseName": "edc-tests" + } + } + ] } - ] + ] + } + ] } diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json new file mode 100644 index 000000000..a47fd8e25 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json @@ -0,0 +1,79 @@ +{ + "description": "find-allowdiskuse-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "3.0.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_find_allowdiskuse_clienterror" + } + } + ], + "tests": [ + { + "description": "Find fails when allowDiskUse true is specified against pre 3.2 server", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "allowDiskUse": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Find fails when allowDiskUse false is specified against pre 3.2 server", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "allowDiskUse": false + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json new file mode 100644 index 000000000..a7907ba25 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json @@ -0,0 +1,100 @@ +{ + "description": "find-allowdiskuse-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.2", + "maxServerVersion": "4.3.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_find_allowdiskuse_servererror" + } + } + ], + "tests": [ + { + "description": "Find fails when allowDiskUse true is specified against pre 4.4 server (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "allowDiskUse": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test_find_allowdiskuse_servererror", + "filter": {}, + "allowDiskUse": true + } + } + } + ] + } + ] + }, + { + "description": "Find fails when allowDiskUse false is specified against pre 4.4 server (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "allowDiskUse": false + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test_find_allowdiskuse_servererror", + "filter": {}, + "allowDiskUse": false + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse.json new file mode 100644 index 000000000..8d4cf66bf --- /dev/null +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse.json @@ -0,0 +1,120 @@ +{ + "description": "find-allowdiskuse", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.1" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_find_allowdiskuse" + } + } + ], + "tests": [ + { + "description": "Find does not send allowDiskuse when value is not specified", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test_find_allowdiskuse", + "allowDiskUse": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "Find sends allowDiskuse false when false is specified", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "allowDiskUse": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test_find_allowdiskuse", + "allowDiskUse": false + } + } + } + ] + } + ] + }, + { + "description": "Find sends allowDiskUse true when true is specified", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": {}, + "allowDiskUse": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test_find_allowdiskuse", + "allowDiskUse": true + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/find.json b/tests/UnifiedSpecTests/crud/find.json new file mode 100644 index 000000000..275d5d351 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/find.json @@ -0,0 +1,156 @@ +{ + "description": "find", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "find-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "find-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "tests": [ + { + "description": "find with multiple batches works", + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2 + }, + "object": "collection0", + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2 + }, + "commandName": "find", + "databaseName": "find-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2 + }, + "commandName": "getMore", + "databaseName": "find-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2 + }, + "commandName": "getMore", + "databaseName": "find-tests" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json new file mode 100644 index 000000000..d04125edd --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json @@ -0,0 +1,133 @@ +{ + "description": "findOneAndDelete-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndDelete_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndDelete with hint string unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndDelete with hint document", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json new file mode 100644 index 000000000..23c01f48f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json @@ -0,0 +1,162 @@ +{ + "description": "findOneAndDelete-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.3.3" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndDelete_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndDelete with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndDelete_hint", + "query": { + "_id": 1 + }, + "hint": "_id_", + "remove": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndDelete with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndDelete_hint", + "query": { + "_id": 1 + }, + "hint": { + "_id": 1 + }, + "remove": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json new file mode 100644 index 000000000..0180010dc --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json @@ -0,0 +1,155 @@ +{ + "description": "findOneAndDelete-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.4" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndDelete_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndDelete with hint string", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndDelete_hint", + "query": { + "_id": 1 + }, + "hint": "_id_", + "remove": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndDelete with hint document", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndDelete_hint", + "query": { + "_id": 1 + }, + "hint": { + "_id": 1 + }, + "remove": true + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json new file mode 100644 index 000000000..c483b2302 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json @@ -0,0 +1,139 @@ +{ + "description": "findOneAndReplace-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndReplace_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndReplace with hint string unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndReplace with hint document unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json new file mode 100644 index 000000000..e8f1c8936 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json @@ -0,0 +1,172 @@ +{ + "description": "findOneAndReplace-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.3.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndReplace_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndReplace with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndReplace_hint", + "query": { + "_id": 1 + }, + "update": { + "x": 33 + }, + "hint": "_id_" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndReplace with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndReplace_hint", + "query": { + "_id": 1 + }, + "update": { + "x": 33 + }, + "hint": { + "_id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json new file mode 100644 index 000000000..13ac6a9c9 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json @@ -0,0 +1,173 @@ +{ + "description": "findOneAndReplace-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.1" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndReplace_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndReplace with hint string", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": "_id_" + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndReplace_hint", + "query": { + "_id": 1 + }, + "update": { + "x": 33 + }, + "hint": "_id_" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 33 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndReplace with hint document", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndReplace_hint", + "query": { + "_id": 1 + }, + "update": { + "x": 33 + }, + "hint": { + "_id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 33 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json new file mode 100644 index 000000000..dace72b0a --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json @@ -0,0 +1,143 @@ +{ + "description": "findOneAndUpdate-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndUpdate_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndUpdate with hint string unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndUpdate with hint document unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json new file mode 100644 index 000000000..1413ced2e --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json @@ -0,0 +1,180 @@ +{ + "description": "findOneAndUpdate-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.3.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndUpdate_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndUpdate with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndUpdate_hint", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndUpdate with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndUpdate_hint", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json new file mode 100644 index 000000000..68cef18ef --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json @@ -0,0 +1,181 @@ +{ + "description": "findOneAndUpdate-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.3.1" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndUpdate_hint" + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "FindOneAndUpdate with hint string", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndUpdate_hint", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "FindOneAndUpdate with hint document", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "_id": 1, + "x": 11 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "findOneAndUpdate_hint", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "findOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 12 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-hint.json b/tests/UnifiedSpecTests/crud/replaceOne-hint.json new file mode 100644 index 000000000..edb1ceb7c --- /dev/null +++ b/tests/UnifiedSpecTests/crud/replaceOne-hint.json @@ -0,0 +1,203 @@ +{ + "description": "replaceOne-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_replaceone_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_replaceone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "ReplaceOne with hint string", + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_replaceone_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "x": 111 + }, + "hint": "_id_", + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_replaceone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 111 + } + ] + } + ] + }, + { + "description": "ReplaceOne with hint document", + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_replaceone_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "x": 111 + }, + "hint": { + "_id": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_replaceone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 111 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-validation.json b/tests/UnifiedSpecTests/crud/replaceOne-validation.json new file mode 100644 index 000000000..56e2de079 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/replaceOne-validation.json @@ -0,0 +1,82 @@ +{ + "description": "replaceOne-validation", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "crud-v2" + } + } + ], + "initialData": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "ReplaceOne prohibits atomic modifiers", + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "$set": { + "x": 22 + } + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/SpecTests/crud/updateMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json similarity index 50% rename from tests/SpecTests/crud/updateMany-hint-clientError.json rename to tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json index 44ebddc53..99c66c919 100644 --- a/tests/SpecTests/crud/updateMany-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json @@ -1,30 +1,61 @@ { - "runOn": [ + "description": "updateMany-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ { "maxServerVersion": "3.3.99" } ], - "data": [ + "createEntities": [ { - "_id": 1, - "x": 11 + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } }, { - "_id": 2, - "x": 22 + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } }, { - "_id": 3, - "x": 33 + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_updatemany_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] } ], - "collection_name": "test_updatemany_hint", "tests": [ { "description": "UpdateMany with hint string unsupported (client-side error)", "operations": [ { - "object": "collection", + "object": "collection0", "name": "updateMany", "arguments": { "filter": { @@ -39,13 +70,22 @@ }, "hint": "_id_" }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -60,13 +100,13 @@ } ] } - } + ] }, { "description": "UpdateMany with hint document unsupported (client-side error)", "operations": [ { - "object": "collection", + "object": "collection0", "name": "updateMany", "arguments": { "filter": { @@ -83,13 +123,22 @@ "_id": 1 } }, - "error": true + "expectError": { + "isError": true + } } ], - "expectations": [], - "outcome": { - "collection": { - "data": [ + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ { "_id": 1, "x": 11 @@ -104,7 +153,7 @@ } ] } - } + ] } ] } diff --git a/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json b/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json new file mode 100644 index 000000000..cc5ecfe26 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json @@ -0,0 +1,216 @@ +{ + "description": "updateMany-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.4.0", + "maxServerVersion": "4.1.9" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_updatemany_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "UpdateMany with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updatemany_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "hint": "_id_", + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "UpdateMany with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updatemany_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "hint": { + "_id": 1 + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateMany-hint.json b/tests/UnifiedSpecTests/crud/updateMany-hint.json new file mode 100644 index 000000000..e5f707fb5 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-hint.json @@ -0,0 +1,219 @@ +{ + "description": "updateMany-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_updatemany_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "UpdateMany with hint string", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updatemany_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "hint": "_id_", + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 34 + } + ] + } + ] + }, + { + "description": "UpdateMany with hint document", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updatemany_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "hint": { + "_id": 1 + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + }, + { + "_id": 3, + "x": 34 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateMany-validation.json b/tests/UnifiedSpecTests/crud/updateMany-validation.json new file mode 100644 index 000000000..45d0b7762 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-validation.json @@ -0,0 +1,98 @@ +{ + "description": "updateMany-validation", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "crud-v2" + } + } + ], + "initialData": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne requires atomic modifiers", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "x": 44 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json new file mode 100644 index 000000000..8c0ddbd1d --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json @@ -0,0 +1,147 @@ +{ + "description": "updateOne-hint-clientError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "maxServerVersion": "3.3.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_updateone_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne with hint string unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateOne with hint document unsupported (client-side error)", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json b/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json new file mode 100644 index 000000000..d8a46da94 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json @@ -0,0 +1,208 @@ +{ + "description": "updateOne-hint-serverError", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "3.4.0", + "maxServerVersion": "4.1.9" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_updateone_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne with hint string unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updateone_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_", + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateOne with hint document unsupported (server-side error)", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updateone_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint.json b/tests/UnifiedSpecTests/crud/updateOne-hint.json new file mode 100644 index 000000000..9277c605f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-hint.json @@ -0,0 +1,211 @@ +{ + "description": "updateOne-hint", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test_updateone_hint" + } + } + ], + "initialData": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne with hint string", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updateone_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_", + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + } + ] + } + ] + }, + { + "description": "UpdateOne with hint document", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test_updateone_hint", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test_updateone_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 23 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-validation.json b/tests/UnifiedSpecTests/crud/updateOne-validation.json new file mode 100644 index 000000000..8336efc0d --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-validation.json @@ -0,0 +1,80 @@ +{ + "description": "updateOne-validation", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "crud-v2" + } + } + ], + "initialData": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne requires atomic modifiers", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "x": 22 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "crud-v2", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateWithPipelines.json b/tests/UnifiedSpecTests/crud/updateWithPipelines.json new file mode 100644 index 000000000..12ae04665 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateWithPipelines.json @@ -0,0 +1,494 @@ +{ + "description": "updateWithPipelines", + "schemaVersion": "1.1", + "runOnRequirements": [ + { + "minServerVersion": "4.1.11" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 1, + "y": 1, + "t": { + "u": { + "v": 1 + } + } + }, + { + "_id": 2, + "x": 2, + "y": 1 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne using pipelines", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceRoot": { + "newRoot": "$t" + } + }, + { + "$addFields": { + "foo": 1 + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceRoot": { + "newRoot": "$t" + } + }, + { + "$addFields": { + "foo": 1 + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + }, + "commandName": "update", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "u": { + "v": 1 + }, + "foo": 1 + }, + { + "_id": 2, + "x": 2, + "y": 1 + } + ] + } + ] + }, + { + "description": "UpdateMany using pipelines", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": {}, + "update": [ + { + "$project": { + "x": 1 + } + }, + { + "$addFields": { + "foo": 1 + } + } + ] + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": {}, + "u": [ + { + "$project": { + "x": 1 + } + }, + { + "$addFields": { + "foo": 1 + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + }, + "commandName": "update", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 1, + "foo": 1 + }, + { + "_id": 2, + "x": 2, + "foo": 1 + } + ] + } + ] + }, + { + "description": "FindOneAndUpdate using pipelines", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$project": { + "x": 1 + } + }, + { + "$addFields": { + "foo": 1 + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "update": [ + { + "$project": { + "x": 1 + } + }, + { + "$addFields": { + "foo": 1 + } + } + ] + }, + "commandName": "findAndModify", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 1, + "foo": 1 + }, + { + "_id": 2, + "x": 2, + "y": 1 + } + ] + } + ] + }, + { + "description": "UpdateOne in bulk write using pipelines", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceRoot": { + "newRoot": "$t" + } + }, + { + "$addFields": { + "foo": 1 + } + } + ] + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceRoot": { + "newRoot": "$t" + } + }, + { + "$addFields": { + "foo": 1 + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + }, + "commandName": "update", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "u": { + "v": 1 + }, + "foo": 1 + }, + { + "_id": 2, + "x": 2, + "y": 1 + } + ] + } + ] + }, + { + "description": "UpdateMany in bulk write using pipelines", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": {}, + "update": [ + { + "$project": { + "x": 1 + } + }, + { + "$addFields": { + "foo": 1 + } + } + ] + } + } + ] + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": {}, + "u": [ + { + "$project": { + "x": 1 + } + }, + { + "$addFields": { + "foo": 1 + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + }, + "commandName": "update", + "databaseName": "crud-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 1, + "foo": 1 + }, + { + "_id": 2, + "x": 2, + "foo": 1 + } + ] + } + ] + } + ] +} From 9ddc272b24969d3b3dc201513eb1598e44b5c57a Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 30 Apr 2021 09:42:42 +0200 Subject: [PATCH 035/321] PHPLIB-634 Ignore pre-release flags in server version numbers (#823) --- tests/FunctionalTestCase.php | 11 ++++------- tests/UnifiedSpecTests/UnifiedTestRunner.php | 3 ++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index cfcdfee0f..4845683d7 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -282,17 +282,14 @@ protected function getPrimaryServer() protected function getServerVersion(ReadPreference $readPreference = null) { - $cursor = $this->manager->executeCommand( + $buildInfo = $this->manager->executeCommand( $this->getDatabaseName(), new Command(['buildInfo' => 1]), $readPreference ?: new ReadPreference(ReadPreference::RP_PRIMARY) - ); - - $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); - $document = current($cursor->toArray()); + )->toArray()[0]; - if (isset($document['version']) && is_string($document['version'])) { - return preg_replace('#^(\d+\.\d+\.\d+).*$#', '\1', $document['version']); + if (isset($buildInfo->version) && is_string($buildInfo->version)) { + return preg_replace('#^(\d+\.\d+\.\d+).*$#', '\1', $buildInfo->version); } throw new UnexpectedValueException('Could not determine server version'); diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 3f9c85f9b..a55697f60 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -25,6 +25,7 @@ use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertNotEmpty; use function preg_match; +use function preg_replace; use function sprintf; use function strpos; use function version_compare; @@ -332,7 +333,7 @@ private function getServerVersion() : string $buildInfo = $database->command(['buildInfo' => 1])->toArray()[0]; if (isset($buildInfo->version) && is_string($buildInfo->version)) { - return $buildInfo->version; + return preg_replace('#^(\d+\.\d+\.\d+).*$#', '\1', $buildInfo->version); } throw new UnexpectedValueException('Could not determine server version'); From df4e32cf506095ef03824638be88b6e06d6e8cc5 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 30 Apr 2021 09:46:55 +0200 Subject: [PATCH 036/321] Run versioned API tests with acceptApiVersion2 (#824) --- .evergreen/config.yml | 16 +++++++++++++--- .evergreen/run-tests.sh | 4 ++++ tests/UnifiedSpecTests/UnifiedSpecTest.php | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index aa63d2cbc..3b9b59268 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -356,7 +356,7 @@ tasks: - func: "run atlas data lake test" - name: "test-requireApiVersion" - tags: ["versioned_api"] + tags: ["versioned-api"] commands: - func: "bootstrap mongo-orchestration" vars: @@ -367,6 +367,16 @@ tasks: vars: API_VERSION: "1" + - name: "test-acceptApiVersion2" + tags: ["versioned-api"] + commands: + - func: "bootstrap mongo-orchestration" + vars: + TOPOLOGY: "server" + ORCHESTRATION_FILE: "versioned-api-testing.json" + - func: "run tests" + vars: + TESTS: "versioned-api" # }}} @@ -619,9 +629,9 @@ buildvariants: tasks: - name: "test-atlas-data-lake" -- matrix_name: "test-requireApiVersion" +- matrix_name: "test-versioned-api" matrix_spec: { "php-edge-versions": "latest-stable", "versions": "latest", "driver-versions": "latest" } display_name: "Versioned API - ${versions}" run_on: rhel70 tasks: - - name: "test-requireApiVersion" + - .versioned-api diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 8842c8ca9..eb78a6893 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -59,6 +59,10 @@ case "$TESTS" in php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --testsuite "Atlas Data Lake Test Suite" $PHPUNIT_OPTS ;; + versioned-api) + php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group versioned-api $PHPUNIT_OPTS + ;; + *) php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml $PHPUNIT_OPTS ;; diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index d17f0c21f..713f717bb 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -85,6 +85,7 @@ public function provideTransactionsTests() /** * @dataProvider provideVersionedApiTests + * @group versioned-api */ public function testVersionedApi(UnifiedTestCase $test) { From aed809ca09ec2728cdc81e51571d846c36eea0bf Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 18 May 2021 12:13:42 -0400 Subject: [PATCH 037/321] PHPLIB-656: Ensure isClientError assertions are handled (#825) --- tests/UnifiedSpecTests/ExpectedError.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index d5c5c322e..1f1bfb639 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -19,6 +19,7 @@ use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsInt; use function PHPUnit\Framework\assertIsString; +use function PHPUnit\Framework\assertNotInstanceOf; use function PHPUnit\Framework\assertNotNull; use function PHPUnit\Framework\assertNull; use function PHPUnit\Framework\assertObjectHasAttribute; @@ -134,6 +135,14 @@ public function assert(Throwable $e = null) assertNotNull($e); + if (isset($this->isClientError)) { + if ($this->isClientError) { + assertNotInstanceOf(ServerException::class, $e); + } else { + assertInstanceOf(ServerException::class, $e); + } + } + if (isset($this->messageContains)) { assertStringContainsStringIgnoringCase($this->messageContains, $e->getMessage()); } From fb40a938d654564a0886e2cac524886a7e982cb0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 18 May 2021 12:13:42 -0400 Subject: [PATCH 038/321] PHPLIB-656: Ensure isClientError assertions are handled (#825) --- tests/UnifiedSpecTests/ExpectedError.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index d5c5c322e..1f1bfb639 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -19,6 +19,7 @@ use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsInt; use function PHPUnit\Framework\assertIsString; +use function PHPUnit\Framework\assertNotInstanceOf; use function PHPUnit\Framework\assertNotNull; use function PHPUnit\Framework\assertNull; use function PHPUnit\Framework\assertObjectHasAttribute; @@ -134,6 +135,14 @@ public function assert(Throwable $e = null) assertNotNull($e); + if (isset($this->isClientError)) { + if ($this->isClientError) { + assertNotInstanceOf(ServerException::class, $e); + } else { + assertInstanceOf(ServerException::class, $e); + } + } + if (isset($this->messageContains)) { assertStringContainsStringIgnoringCase($this->messageContains, $e->getMessage()); } From a66f31f3fab2c9b08402770489e0f88d44dce9f3 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 18 May 2021 13:04:09 -0400 Subject: [PATCH 039/321] PHPLIB-657: Skip incompatible unified tests and resync CRUD (#826) * PHPLIB-657: Allow UnifiedSpecTest to mark incompatible tests as incomplete * PHPLIB-645: Sync unified CRUD tests This restores several missing tests and skips incompatible tests for unacknowledged writes using hint. The db-aggregate tests will also be skipped until schemaVersion 1.4 is implemented (serverless testing). Synced with mongodb/specifications@c06e4c0a222f72071cb53f5949cd1c5fa30f6d7f --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 40 ++- tests/UnifiedSpecTests/crud/aggregate.json | 166 ++++++++++ tests/UnifiedSpecTests/crud/db-aggregate.json | 5 +- ...ged-bulkWrite-delete-hint-clientError.json | 193 ++++++++++++ ...ged-bulkWrite-update-hint-clientError.json | 284 ++++++++++++++++++ ...nowledged-deleteMany-hint-clientError.json | 149 +++++++++ ...knowledged-deleteOne-hint-clientError.json | 133 ++++++++ ...ged-findOneAndDelete-hint-clientError.json | 133 ++++++++ ...ed-findOneAndReplace-hint-clientError.json | 139 +++++++++ ...ged-findOneAndUpdate-hint-clientError.json | 143 +++++++++ ...nowledged-replaceOne-hint-clientError.json | 143 +++++++++ ...nowledged-updateMany-hint-clientError.json | 159 ++++++++++ ...knowledged-updateOne-hint-clientError.json | 147 +++++++++ 13 files changed, 1831 insertions(+), 3 deletions(-) create mode 100644 tests/UnifiedSpecTests/crud/aggregate.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 713f717bb..a11e672f2 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -8,6 +8,8 @@ use PHPUnit\Framework\SkippedTest; use PHPUnit\Framework\Warning; use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; +use function basename; +use function dirname; use function glob; /** @@ -19,6 +21,31 @@ class UnifiedSpecTest extends FunctionalTestCase { use SetUpTearDownTrait; + /** @var array */ + private static $incompleteTests = [ + 'crud/unacknowledged-bulkWrite-delete-hint-clientError: Unacknowledged bulkWrite deleteOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-bulkWrite-delete-hint-clientError: Unacknowledged bulkWrite deleteMany with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite updateOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite updateMany with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite replaceOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-deleteMany-hint-clientError: Unacknowledged deleteMany with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-deleteMany-hint-clientError: Unacknowledged deleteMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-deleteOne-hint-clientError: Unacknowledged deleteOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-deleteOne-hint-clientError: Unacknowledged deleteOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-findOneAndDelete-hint-clientError: Unacknowledged findOneAndDelete with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-findOneAndDelete-hint-clientError: Unacknowledged findOneAndDelete with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-findOneAndReplace-hint-clientError: Unacknowledged findOneAndReplace with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-findOneAndReplace-hint-clientError: Unacknowledged findOneAndReplace with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-findOneAndUpdate-hint-clientError: Unacknowledged findOneAndUpdate with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-findOneAndUpdate-hint-clientError: Unacknowledged findOneAndUpdate with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-replaceOne-hint-clientError: Unacknowledged ReplaceOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-replaceOne-hint-clientError: Unacknowledged ReplaceOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + ]; + /** @var UnifiedTestRunner */ private static $runner; @@ -31,6 +58,15 @@ private static function doSetUpBeforeClass() self::$runner = new UnifiedTestRunner(static::getUri(true)); } + private function doSetUp() + { + parent::setUp(); + + if (isset(self::$incompleteTests[$this->dataDescription()])) { + $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); + } + } + /** * @dataProvider provideChangeStreamsTests */ @@ -147,8 +183,10 @@ public function provideFailingTests() private function provideTests(string $pattern) : Generator { foreach (glob($pattern) as $filename) { + $group = basename(dirname($filename)); + foreach (UnifiedTestCase::fromFile($filename) as $name => $test) { - yield $name => [$test]; + yield $group . '/' . $name => [$test]; } } } diff --git a/tests/UnifiedSpecTests/crud/aggregate.json b/tests/UnifiedSpecTests/crud/aggregate.json new file mode 100644 index 000000000..dcdad761e --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate.json @@ -0,0 +1,166 @@ +{ + "description": "aggregate", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "aggregate-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "aggregate-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "tests": [ + { + "description": "aggregate with multiple batches works", + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "batchSize": 2 + }, + "object": "collection0", + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "cursor": { + "batchSize": 2 + } + }, + "commandName": "aggregate", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2 + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2 + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/db-aggregate.json b/tests/UnifiedSpecTests/crud/db-aggregate.json index 6ae029175..5015405bf 100644 --- a/tests/UnifiedSpecTests/crud/db-aggregate.json +++ b/tests/UnifiedSpecTests/crud/db-aggregate.json @@ -1,9 +1,10 @@ { "description": "db-aggregate", - "schemaVersion": "1.1", + "schemaVersion": "1.4", "runOnRequirements": [ { - "minServerVersion": "3.6.0" + "minServerVersion": "3.6.0", + "serverless": "forbid" } ], "createEntities": [ diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json new file mode 100644 index 000000000..dca810810 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json @@ -0,0 +1,193 @@ +{ + "description": "unacknowledged-bulkWrite-delete-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "BulkWrite_delete_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged bulkWrite deleteOne with hints fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + } + }, + { + "deleteOne": { + "filter": { + "_id": 2 + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "Unacknowledged bulkWrite deleteMany with hints fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "hint": "_id_" + } + }, + { + "deleteMany": { + "filter": { + "_id": { + "$gte": 4 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_delete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json new file mode 100644 index 000000000..22377b9ac --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json @@ -0,0 +1,284 @@ +{ + "description": "unacknowledged-bulkWrite-update-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "Bulkwrite_update_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "Bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged bulkWrite updateOne with hints fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + }, + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "Bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "Unacknowledged bulkWrite updateMany with hints fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + }, + { + "updateMany": { + "filter": { + "_id": { + "$lt": 3 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "Bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + }, + { + "description": "Unacknowledged bulkWrite replaceOne with hints fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 3 + }, + "replacement": { + "x": 333 + }, + "hint": "_id_" + } + }, + { + "replaceOne": { + "filter": { + "_id": 4 + }, + "replacement": { + "x": 444 + }, + "hint": { + "_id": 1 + } + } + } + ], + "ordered": true + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "Bulkwrite_update_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json new file mode 100644 index 000000000..21776eae8 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json @@ -0,0 +1,149 @@ +{ + "description": "unacknowledged-deleteMany-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteMany_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged deleteMany with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteMany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json new file mode 100644 index 000000000..870c08339 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json @@ -0,0 +1,133 @@ +{ + "description": "unacknowledged-deleteOne-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "DeleteOne_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged deleteOne with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "DeleteOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json new file mode 100644 index 000000000..a19cd7763 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json @@ -0,0 +1,133 @@ +{ + "description": "unacknowledged-findOneAndDelete-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "findOneAndDelete_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged findOneAndDelete with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "Unacknowledged findOneAndDelete with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": 1 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "findOneAndDelete_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json new file mode 100644 index 000000000..c60bfdef1 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json @@ -0,0 +1,139 @@ +{ + "description": "unacknowledged-findOneAndReplace-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "FindOneAndReplace_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "FindOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged findOneAndReplace with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "FindOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "Unacknowledged findOneAndReplace with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 33 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "FindOneAndReplace_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json new file mode 100644 index 000000000..506510a3c --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json @@ -0,0 +1,143 @@ +{ + "description": "unacknowledged-findOneAndUpdate-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "FindOneAndUpdate_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "FindOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged findOneAndUpdate with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "FindOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "Unacknowledged findOneAndUpdate with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "FindOneAndUpdate_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json new file mode 100644 index 000000000..b4f4bed5f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json @@ -0,0 +1,143 @@ +{ + "description": "unacknowledged-replaceOne-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "ReplaceOne_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "ReplaceOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged ReplaceOne with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "ReplaceOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "Unacknowledged ReplaceOne with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "ReplaceOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json new file mode 100644 index 000000000..3087dc4db --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json @@ -0,0 +1,159 @@ +{ + "description": "unacknowledged-updateMany-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "Updatemany_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "Updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged updateMany with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "Updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "Updatemany_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json new file mode 100644 index 000000000..208703c26 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json @@ -0,0 +1,147 @@ +{ + "description": "unacknowledged-updateOne-hint-clientError", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "UpdateOne_hint", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "UpdateOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged updateOne with hint string fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "UpdateOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint document fails with client-side error", + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ], + "outcome": [ + { + "collectionName": "UpdateOne_hint", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} From 0fae16ffbff938eec6b49881f2f95f1951eb8221 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Sat, 22 May 2021 19:15:44 +0200 Subject: [PATCH 040/321] PHPLIB-653 Add versioned API connection examples for docs (#827) --- tests/DocumentationExamplesTest.php | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index c3a68492c..9974a6751 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1550,6 +1550,36 @@ public function testCausalConsistency() ob_end_clean(); } + /** + * @doesNotPerformAssertions + */ + public function testVersionedApi() + { + $uriString = static::getUri(true); + + // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly + // Start Versioned API Example 1 + $serverApi = new \MongoDB\Driver\ServerApi('1'); + $client = new \MongoDB\Client($uriString, [], ['serverApi' => $serverApi]); + // End Versioned API Example 1 + + // Start Versioned API Example 2 + $serverApi = new \MongoDB\Driver\ServerApi('1', true); + $client = new \MongoDB\Client($uriString, [], ['serverApi' => $serverApi]); + // End Versioned API Example 2 + + // Start Versioned API Example 3 + $serverApi = new \MongoDB\Driver\ServerApi('1', false); + $client = new \MongoDB\Client($uriString, [], ['serverApi' => $serverApi]); + // End Versioned API Example 3 + + // Start Versioned API Example 4 + $serverApi = new \MongoDB\Driver\ServerApi('1', false, true); + $client = new \MongoDB\Client($uriString, [], ['serverApi' => $serverApi]); + // End Versioned API Example 4 + // phpcs:enable + } + /** * @doesNotPerformAssertions */ From fabe3daa57492fa92943480972aaba429b5e8c50 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 3 Jun 2021 14:38:09 -0400 Subject: [PATCH 041/321] PHPLIB-663: Support let option for aggregate command (#830) Syncs CRUD unified spec tests with mongodb/specifications@3db387995bc0e64df862d621aaa31387afc1537c --- src/Operation/Aggregate.php | 18 +- tests/Operation/AggregateTest.php | 4 + tests/UnifiedSpecTests/UnifiedSpecTest.php | 61 ++ .../UnifiedSpecTests/crud/aggregate-let.json | 195 ++++++ .../crud/aggregate-merge.json | 2 +- .../crud/aggregate-out-readConcern.json | 2 +- .../bulkWrite-arrayFilters-clientError.json | 2 +- .../crud/bulkWrite-arrayFilters.json | 10 +- .../bulkWrite-delete-hint-clientError.json | 2 +- .../bulkWrite-delete-hint-serverError.json | 2 +- .../crud/bulkWrite-delete-hint.json | 10 +- .../bulkWrite-insertOne-dots_and_dollars.json | 374 +++++++++++ ...bulkWrite-replaceOne-dots_and_dollars.json | 532 +++++++++++++++ .../bulkWrite-update-hint-clientError.json | 2 +- .../bulkWrite-update-hint-serverError.json | 2 +- .../crud/bulkWrite-update-hint.json | 14 +- .../crud/bulkWrite-update-validation.json | 34 +- ...bulkWrite-updateMany-dots_and_dollars.json | 452 +++++++++++++ .../bulkWrite-updateOne-dots_and_dollars.json | 460 +++++++++++++ .../crud/deleteMany-hint-clientError.json | 2 +- .../crud/deleteMany-hint-serverError.json | 2 +- .../crud/deleteMany-hint.json | 2 +- .../crud/deleteOne-hint-clientError.json | 2 +- .../crud/deleteOne-hint-serverError.json | 2 +- .../UnifiedSpecTests/crud/deleteOne-hint.json | 2 +- .../crud/find-allowdiskuse-clientError.json | 2 +- .../crud/find-allowdiskuse-serverError.json | 2 +- .../crud/find-allowdiskuse.json | 2 +- .../findOneAndDelete-hint-clientError.json | 2 +- .../findOneAndDelete-hint-serverError.json | 2 +- .../crud/findOneAndDelete-hint.json | 2 +- .../findOneAndReplace-dots_and_dollars.json | 430 +++++++++++++ .../findOneAndReplace-hint-clientError.json | 2 +- .../findOneAndReplace-hint-serverError.json | 2 +- .../crud/findOneAndReplace-hint.json | 2 +- .../findOneAndUpdate-dots_and_dollars.json | 380 +++++++++++ .../findOneAndUpdate-hint-clientError.json | 2 +- .../findOneAndUpdate-hint-serverError.json | 2 +- .../crud/findOneAndUpdate-hint.json | 2 +- .../crud/insertMany-dots_and_dollars.json | 334 ++++++++++ .../crud/insertOne-dots_and_dollars.json | 606 ++++++++++++++++++ .../crud/replaceOne-dots_and_dollars.json | 567 ++++++++++++++++ .../crud/replaceOne-hint.json | 2 +- .../crud/replaceOne-validation.json | 18 +- ...ged-bulkWrite-delete-hint-clientError.json | 2 +- ...ged-bulkWrite-update-hint-clientError.json | 2 +- ...nowledged-deleteMany-hint-clientError.json | 2 +- ...knowledged-deleteOne-hint-clientError.json | 2 +- ...ged-findOneAndDelete-hint-clientError.json | 2 +- ...ed-findOneAndReplace-hint-clientError.json | 2 +- ...ged-findOneAndUpdate-hint-clientError.json | 2 +- ...nowledged-replaceOne-hint-clientError.json | 2 +- ...nowledged-updateMany-hint-clientError.json | 2 +- ...knowledged-updateOne-hint-clientError.json | 2 +- .../crud/updateMany-dots_and_dollars.json | 404 ++++++++++++ .../crud/updateMany-hint-clientError.json | 2 +- .../crud/updateMany-hint-serverError.json | 2 +- .../crud/updateMany-hint.json | 2 +- .../crud/updateMany-validation.json | 20 +- .../crud/updateOne-dots_and_dollars.json | 412 ++++++++++++ .../crud/updateOne-hint-clientError.json | 2 +- .../crud/updateOne-hint-serverError.json | 2 +- .../UnifiedSpecTests/crud/updateOne-hint.json | 2 +- .../crud/updateOne-validation.json | 18 +- .../crud/updateWithPipelines.json | 2 +- 65 files changed, 5339 insertions(+), 100 deletions(-) create mode 100644 tests/UnifiedSpecTests/crud/aggregate-let.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-insertOne-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-updateMany-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-updateOne-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/replaceOne-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/updateMany-dots_and_dollars.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-dots_and_dollars.json diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 85df84b44..0a9e77791 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -107,6 +107,14 @@ class Aggregate implements Executable, Explainable * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * + * This is not supported for server versions < 5.0 and will result in an + * exception at execution time if used. + * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * @@ -196,6 +204,10 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr throw InvalidArgumentException::invalidType('"hint" option', $options['hint'], 'string or array or object'); } + if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { + throw InvalidArgumentException::invalidType('"let" option', $options['let'], ['array', 'object']); + } + if (isset($options['maxAwaitTimeMS']) && ! is_integer($options['maxAwaitTimeMS'])) { throw InvalidArgumentException::invalidType('"maxAwaitTimeMS" option', $options['maxAwaitTimeMS'], 'integer'); } @@ -344,8 +356,10 @@ private function createCommandDocument(Server $server, bool $hasWriteStage) : ar } } - if (isset($this->options['collation'])) { - $cmd['collation'] = (object) $this->options['collation']; + foreach (['collation', 'let'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = (object) $this->options[$option]; + } } if (isset($this->options['hint'])) { diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php index d8898b321..e165a7f7e 100644 --- a/tests/Operation/AggregateTest.php +++ b/tests/Operation/AggregateTest.php @@ -51,6 +51,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['hint' => $value]; } + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['let' => $value]; + } + foreach ($this->getInvalidBooleanValues() as $value) { $options[][] = ['explain' => $value]; } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index a11e672f2..a27753621 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -23,6 +23,7 @@ class UnifiedSpecTest extends FunctionalTestCase /** @var array */ private static $incompleteTests = [ + // PHPLIB-573 and DRIVERS-1340 'crud/unacknowledged-bulkWrite-delete-hint-clientError: Unacknowledged bulkWrite deleteOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-bulkWrite-delete-hint-clientError: Unacknowledged bulkWrite deleteMany with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite updateOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', @@ -44,6 +45,66 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + // CDRIVER-3895 and PHPC-1765 + 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with top-level dotted key' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with dollar-prefixed key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with dotted key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with top-level dotted key on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with top-level dotted key on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndReplace-dots_and_dollars: Replacing document with top-level dotted key on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndReplace-dots_and_dollars: Replacing document with top-level dotted key on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dotted key in embedded doc on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertMany-dots_and_dollars: Inserting document with top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertMany-dots_and_dollars: Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertMany-dots_and_dollars: Inserting document with top-level dotted key' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertMany-dots_and_dollars: Inserting document with dollar-prefixed key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertMany-dots_and_dollars: Inserting document with dotted key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with top-level dotted key' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with dollar-prefixed key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with dotted key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with dollar-prefixed key in _id yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with dotted key in _id on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with dotted key in _id on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Inserting document with DBRef-like keys' => 'CDRIVER-3895 and PHPC-1765', + 'crud/insertOne-dots_and_dollars: Unacknowledged write using dollar-prefixed or dotted keys may be silently rejected on pre-5.0 server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Replacing document with top-level dotted key on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Replacing document with top-level dotted key on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', + 'crud/replaceOne-dots_and_dollars: Unacknowledged write using dollar-prefixed or dotted keys may be silently rejected on pre-5.0 server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateMany-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateMany-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateMany-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateMany-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateOne-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateOne-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateOne-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'crud/updateOne-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/crud/aggregate-let.json b/tests/UnifiedSpecTests/crud/aggregate-let.json new file mode 100644 index 000000000..f31c6ee9d --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate-let.json @@ -0,0 +1,195 @@ +{ + "description": "aggregate-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "Aggregate with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 0, + "x": "$$x", + "y": "$$y", + "rand": "$$rand" + } + } + ], + "let": { + "id": 1, + "x": "foo", + "y": { + "$literal": "$bar" + }, + "rand": { + "$rand": {} + } + } + }, + "expectResult": [ + { + "x": "foo", + "y": "$bar", + "rand": { + "$$type": "double" + } + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 0, + "x": "$$x", + "y": "$$y", + "rand": "$$rand" + } + } + ], + "let": { + "id": 1, + "x": "foo", + "y": { + "$literal": "$bar" + }, + "rand": { + "$rand": {} + } + } + } + } + } + ] + } + ] + }, + { + "description": "Aggregate with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "2.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "let": { + "x": "foo" + } + }, + "expectError": { + "errorContains": "unrecognized field 'let'", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "let": { + "x": "foo" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/aggregate-merge.json b/tests/UnifiedSpecTests/crud/aggregate-merge.json index c34e93a69..ac61ceb8a 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-merge.json +++ b/tests/UnifiedSpecTests/crud/aggregate-merge.json @@ -1,6 +1,6 @@ { "description": "aggregate-merge", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.1.11" diff --git a/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json b/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json index ae1beedde..9f0a9688e 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json +++ b/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json @@ -1,6 +1,6 @@ { "description": "aggregate-out-readConcern", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.1.0", diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json index 6073890dd..63815e323 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters-clientError.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-arrayFilters-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.5.5" diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json index 8a68f51d1..70ee014f7 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-arrayFilters.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-arrayFilters", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.5.6" @@ -90,7 +90,9 @@ "expectResult": { "deletedCount": 0, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 1, "modifiedCount": 1, "upsertedCount": 0, @@ -196,7 +198,9 @@ "expectResult": { "deletedCount": 0, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 2, "modifiedCount": 2, "upsertedCount": 0, diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json index c55067be2..2961b55dc 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-delete-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.3.99" diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json index 30b9010ac..fa9952209 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-delete-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.4.0", diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json index c892457a6..9fcdecefd 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-delete-hint.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-delete-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.4" @@ -87,7 +87,9 @@ "expectResult": { "deletedCount": 2, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 0, "modifiedCount": 0, "upsertedCount": 0, @@ -181,7 +183,9 @@ "expectResult": { "deletedCount": 3, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 0, "modifiedCount": 0, "upsertedCount": 0, diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-insertOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/bulkWrite-insertOne-dots_and_dollars.json new file mode 100644 index 000000000..92bbb1aaf --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-insertOne-dots_and_dollars.json @@ -0,0 +1,374 @@ +{ + "description": "bulkWrite-insertOne-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "Inserting document with top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 1, + "$a": 1 + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + }, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 1, + "$a": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ] + }, + { + "description": "Inserting document with top-level dotted key", + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 1, + "a.b": 1 + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + }, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Inserting document with dollar-prefixed key in embedded doc", + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 1, + "a": { + "$b": 1 + } + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + }, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + ] + }, + { + "description": "Inserting document with dotted key in embedded doc", + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 1, + "a": { + "b.c": 1 + } + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + }, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-dots_and_dollars.json new file mode 100644 index 000000000..fce647d8f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-dots_and_dollars.json @@ -0,0 +1,532 @@ +{ + "description": "bulkWrite-replaceOne-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "Replacing document with top-level dotted key on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a.b": 1 + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a.b": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with top-level dotted key on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a.b": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a.b": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + ] + }, + { + "description": "Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + } + } + ] + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with dotted key in embedded doc on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "b.c": 1 + } + } + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "b.c": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + ] + }, + { + "description": "Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "b.c": 1 + } + } + } + } + ] + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "b.c": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json index 68a92065a..d5eb71c29 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-update-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.3.99" diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json index 2a9a6795c..b0f7e1b38 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-update-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.4.0", diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json index 32e3787ff..420635989 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-hint.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-update-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0" @@ -97,7 +97,9 @@ "expectResult": { "deletedCount": 0, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 2, "modifiedCount": 2, "upsertedCount": 0, @@ -229,7 +231,9 @@ "expectResult": { "deletedCount": 0, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 4, "modifiedCount": 4, "upsertedCount": 0, @@ -353,7 +357,9 @@ "expectResult": { "deletedCount": 0, "insertedCount": 0, - "insertedIds": {}, + "insertedIds": { + "$$unsetOrMatches": {} + }, "matchedCount": 2, "modifiedCount": 2, "upsertedCount": 0, diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json b/tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json index 9ed7db512..f9bfda0ed 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-update-validation.json @@ -1,6 +1,6 @@ { "description": "bulkWrite-update-validation", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { @@ -14,21 +14,21 @@ "database": { "id": "database0", "client": "client0", - "databaseName": "crud-v2" + "databaseName": "crud-tests" } }, { "collection": { "id": "collection0", "database": "database0", - "collectionName": "crud-v2" + "collectionName": "coll0" } } ], "initialData": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, @@ -50,8 +50,8 @@ "description": "BulkWrite replaceOne prohibits atomic modifiers", "operations": [ { - "object": "collection0", "name": "bulkWrite", + "object": "collection0", "arguments": { "requests": [ { @@ -69,7 +69,7 @@ ] }, "expectError": { - "isError": true + "isClientError": true } } ], @@ -81,8 +81,8 @@ ], "outcome": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, @@ -104,8 +104,8 @@ "description": "BulkWrite updateOne requires atomic modifiers", "operations": [ { - "object": "collection0", "name": "bulkWrite", + "object": "collection0", "arguments": { "requests": [ { @@ -121,7 +121,7 @@ ] }, "expectError": { - "isError": true + "isClientError": true } } ], @@ -133,8 +133,8 @@ ], "outcome": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, @@ -156,8 +156,8 @@ "description": "BulkWrite updateMany requires atomic modifiers", "operations": [ { - "object": "collection0", "name": "bulkWrite", + "object": "collection0", "arguments": { "requests": [ { @@ -175,7 +175,7 @@ ] }, "expectError": { - "isError": true + "isClientError": true } } ], @@ -187,8 +187,8 @@ ], "outcome": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-dots_and_dollars.json new file mode 100644 index 000000000..35a5cdd52 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-dots_and_dollars.json @@ -0,0 +1,452 @@ +{ + "description": "bulkWrite-updateMany-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {} + } + ] + } + ], + "tests": [ + { + "description": "Updating document to set top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set top-level dotted key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "$a": 1 + } + } + ] + } + ] + }, + { + "description": "Updating document to set dotted key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "a.b": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-dots_and_dollars.json new file mode 100644 index 000000000..cbbe113ce --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-dots_and_dollars.json @@ -0,0 +1,460 @@ +{ + "description": "bulkWrite-updateOne-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {} + } + ] + } + ], + "tests": [ + { + "description": "Updating document to set top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set top-level dotted key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "$a": 1 + } + } + ] + } + ] + }, + { + "description": "Updating document to set dotted key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + } + } + ] + }, + "expectResult": { + "deletedCount": 0, + "insertedCount": 0, + "insertedIds": { + "$$unsetOrMatches": {} + }, + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "a.b": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json index 285f567f0..66320122b 100644 --- a/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "deleteMany-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.3.99" diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json b/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json index 90bfb89fc..88d4a6557 100644 --- a/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "deleteMany-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.4.0", diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint.json b/tests/UnifiedSpecTests/crud/deleteMany-hint.json index b0cdc0304..59d903d20 100644 --- a/tests/UnifiedSpecTests/crud/deleteMany-hint.json +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint.json @@ -1,6 +1,6 @@ { "description": "deleteMany-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.4" diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json index b6b2932bd..cf629f59e 100644 --- a/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "deleteOne-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.3.99" diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json b/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json index 8b1398c75..15541ed85 100644 --- a/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "deleteOne-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.4.0", diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint.json b/tests/UnifiedSpecTests/crud/deleteOne-hint.json index 9e3970a54..bcc4bc234 100644 --- a/tests/UnifiedSpecTests/crud/deleteOne-hint.json +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint.json @@ -1,6 +1,6 @@ { "description": "deleteOne-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.4" diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json index a47fd8e25..5bd954e79 100644 --- a/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse-clientError.json @@ -1,6 +1,6 @@ { "description": "find-allowdiskuse-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.0.99" diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json index a7907ba25..dc58f8f0e 100644 --- a/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse-serverError.json @@ -1,6 +1,6 @@ { "description": "find-allowdiskuse-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.2", diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse.json index 8d4cf66bf..789bb7fbf 100644 --- a/tests/UnifiedSpecTests/crud/find-allowdiskuse.json +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse.json @@ -1,6 +1,6 @@ { "description": "find-allowdiskuse", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.1" diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json index d04125edd..c6ff46786 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "findOneAndDelete-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "4.0.99" diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json index 23c01f48f..b87410272 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "findOneAndDelete-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0", diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json index 0180010dc..8b53f2bd3 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint.json @@ -1,6 +1,6 @@ { "description": "findOneAndDelete-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.4" diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-dots_and_dollars.json new file mode 100644 index 000000000..19ac447f8 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-dots_and_dollars.json @@ -0,0 +1,430 @@ +{ + "description": "findOneAndReplace-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "Replacing document with top-level dotted key on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a.b": 1 + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "_id": 1, + "a.b": 1 + }, + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with top-level dotted key on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a.b": 1 + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "_id": 1, + "a.b": 1 + }, + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + ] + }, + { + "description": "Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with dotted key in embedded doc on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "b.c": 1 + } + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "_id": 1, + "a": { + "b.c": 1 + } + }, + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + ] + }, + { + "description": "Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "b.c": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "_id": 1, + "a": { + "b.c": 1 + } + }, + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json index c483b2302..6b07eb1f4 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "findOneAndReplace-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "4.0.99" diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json index e8f1c8936..7fbf5a0ea 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "findOneAndReplace-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0", diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json index 13ac6a9c9..d07c5921a 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint.json @@ -1,6 +1,6 @@ { "description": "findOneAndReplace-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.1" diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-dots_and_dollars.json new file mode 100644 index 000000000..40eb54739 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-dots_and_dollars.json @@ -0,0 +1,380 @@ +{ + "description": "findOneAndUpdate-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {} + } + ] + } + ], + "tests": [ + { + "description": "Updating document to set top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + }, + "expectResult": { + "_id": 1, + "foo": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set top-level dotted key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + }, + "expectResult": { + "_id": 1, + "foo": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + }, + "expectResult": { + "_id": 1, + "foo": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "$a": 1 + } + } + ] + } + ] + }, + { + "description": "Updating document to set dotted key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + }, + "expectResult": { + "_id": 1, + "foo": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "new": { + "$$unsetOrMatches": false + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "a.b": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json index dace72b0a..d0b51313c 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "findOneAndUpdate-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "4.0.99" diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json index 1413ced2e..99fd9938f 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "findOneAndUpdate-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0", diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json index 68cef18ef..5be6d2b3e 100644 --- a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint.json @@ -1,6 +1,6 @@ { "description": "findOneAndUpdate-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.3.1" diff --git a/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json new file mode 100644 index 000000000..3b66ac062 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json @@ -0,0 +1,334 @@ +{ + "description": "insertMany-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "Inserting document with top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + }, + "expectResult": { + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ] + }, + { + "description": "Inserting document with top-level dotted key", + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + }, + "expectResult": { + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Inserting document with dollar-prefixed key in embedded doc", + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + }, + "expectResult": { + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + ] + }, + { + "description": "Inserting document with dotted key in embedded doc", + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + }, + "expectResult": { + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json new file mode 100644 index 000000000..1a30df4a0 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json @@ -0,0 +1,606 @@ +{ + "description": "insertOne-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "Inserting document with top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "$a": 1 + } + }, + "expectResult": { + "insertedCount": 1, + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "$a": 1 + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "$a": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ] + }, + { + "description": "Inserting document with top-level dotted key", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a.b": 1 + } + }, + "expectResult": { + "insertedCount": 1, + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Inserting document with dollar-prefixed key in embedded doc", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": { + "$b": 1 + } + } + }, + "expectResult": { + "insertedCount": 1, + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + ] + }, + { + "description": "Inserting document with dotted key in embedded doc", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": { + "b.c": 1 + } + } + }, + "expectResult": { + "insertedCount": 1, + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + ] + }, + { + "description": "Inserting document with dollar-prefixed key in _id yields server-side error", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": { + "$a": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": { + "$a": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ] + }, + { + "description": "Inserting document with dotted key in _id on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": { + "a.b": 1 + } + } + }, + "expectResult": { + "insertedCount": 1, + "insertedId": { + "$$unsetOrMatches": { + "a.b": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": { + "a.b": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": { + "a.b": 1 + } + } + ] + } + ] + }, + { + "description": "Inserting document with dotted key in _id on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": { + "a.b": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": { + "a.b": 1 + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ] + }, + { + "description": "Inserting document with DBRef-like keys", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": { + "$db": "foo" + } + } + }, + "expectResult": { + "insertedCount": 1, + "insertedId": { + "$$unsetOrMatches": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1, + "a": { + "$db": "foo" + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$db": "foo" + } + } + ] + } + ] + }, + { + "description": "Unacknowledged write using dollar-prefixed or dotted keys may be silently rejected on pre-5.0 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection1", + "arguments": { + "document": { + "_id": { + "$a": 1 + } + } + }, + "expectResult": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll1", + "documents": [ + { + "_id": { + "$a": 1 + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/replaceOne-dots_and_dollars.json new file mode 100644 index 000000000..d5003dc5e --- /dev/null +++ b/tests/UnifiedSpecTests/crud/replaceOne-dots_and_dollars.json @@ -0,0 +1,567 @@ +{ + "description": "replaceOne-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "Replacing document with top-level dotted key on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a.b": 1 + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a.b": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with top-level dotted key on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a.b": 1 + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a.b": 1 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "$b": 1 + } + } + ] + } + ] + }, + { + "description": "Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Replacing document with dotted key in embedded doc on 3.6+ server", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "b.c": 1 + } + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "b.c": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "a": { + "b.c": 1 + } + } + ] + } + ] + }, + { + "description": "Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error", + "runOnRequirements": [ + { + "maxServerVersion": "3.4.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "b.c": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "b.c": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Unacknowledged write using dollar-prefixed or dotted keys may be silently rejected on pre-5.0 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection1", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "a": { + "$b": 1 + } + } + }, + "expectResult": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll1", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "a": { + "$b": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-hint.json b/tests/UnifiedSpecTests/crud/replaceOne-hint.json index edb1ceb7c..6926e9d8d 100644 --- a/tests/UnifiedSpecTests/crud/replaceOne-hint.json +++ b/tests/UnifiedSpecTests/crud/replaceOne-hint.json @@ -1,6 +1,6 @@ { "description": "replaceOne-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0" diff --git a/tests/UnifiedSpecTests/crud/replaceOne-validation.json b/tests/UnifiedSpecTests/crud/replaceOne-validation.json index 56e2de079..6f5b173e0 100644 --- a/tests/UnifiedSpecTests/crud/replaceOne-validation.json +++ b/tests/UnifiedSpecTests/crud/replaceOne-validation.json @@ -1,6 +1,6 @@ { "description": "replaceOne-validation", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { @@ -14,21 +14,21 @@ "database": { "id": "database0", "client": "client0", - "databaseName": "crud-v2" + "databaseName": "crud-tests" } }, { "collection": { "id": "collection0", "database": "database0", - "collectionName": "crud-v2" + "collectionName": "coll0" } } ], "initialData": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, @@ -42,8 +42,8 @@ "description": "ReplaceOne prohibits atomic modifiers", "operations": [ { - "object": "collection0", "name": "replaceOne", + "object": "collection0", "arguments": { "filter": { "_id": 1 @@ -55,7 +55,7 @@ } }, "expectError": { - "isError": true + "isClientError": true } } ], @@ -67,8 +67,8 @@ ], "outcome": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json index dca810810..dbaa2e84f 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-bulkWrite-delete-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json index 22377b9ac..858967b90 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-bulkWrite-update-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json index 21776eae8..c5d9f6af3 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-deleteMany-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json index 870c08339..177ad889b 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-deleteOne-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json index a19cd7763..6ee59cdf6 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-findOneAndDelete-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json index c60bfdef1..15ca77322 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-findOneAndReplace-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json index 506510a3c..e18767f8b 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-findOneAndUpdate-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json index b4f4bed5f..52ec59d0c 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-replaceOne-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json index 3087dc4db..6199dfa2b 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-updateMany-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json index 208703c26..3828a9e8d 100644 --- a/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "unacknowledged-updateOne-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/crud/updateMany-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/updateMany-dots_and_dollars.json new file mode 100644 index 000000000..5d3b9d045 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-dots_and_dollars.json @@ -0,0 +1,404 @@ +{ + "description": "updateMany-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {} + } + ] + } + ], + "tests": [ + { + "description": "Updating document to set top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set top-level dotted key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "$a": 1 + } + } + ] + } + ] + }, + { + "description": "Updating document to set dotted key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "a.b": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json index 99c66c919..5da878e29 100644 --- a/tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/updateMany-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "updateMany-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.3.99" diff --git a/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json b/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json index cc5ecfe26..c81f36b13 100644 --- a/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/updateMany-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "updateMany-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.4.0", diff --git a/tests/UnifiedSpecTests/crud/updateMany-hint.json b/tests/UnifiedSpecTests/crud/updateMany-hint.json index e5f707fb5..929be5299 100644 --- a/tests/UnifiedSpecTests/crud/updateMany-hint.json +++ b/tests/UnifiedSpecTests/crud/updateMany-hint.json @@ -1,6 +1,6 @@ { "description": "updateMany-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0" diff --git a/tests/UnifiedSpecTests/crud/updateMany-validation.json b/tests/UnifiedSpecTests/crud/updateMany-validation.json index 45d0b7762..e3e46a138 100644 --- a/tests/UnifiedSpecTests/crud/updateMany-validation.json +++ b/tests/UnifiedSpecTests/crud/updateMany-validation.json @@ -1,6 +1,6 @@ { "description": "updateMany-validation", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { @@ -14,21 +14,21 @@ "database": { "id": "database0", "client": "client0", - "databaseName": "crud-v2" + "databaseName": "crud-tests" } }, { "collection": { "id": "collection0", "database": "database0", - "collectionName": "crud-v2" + "collectionName": "coll0" } } ], "initialData": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, @@ -47,11 +47,11 @@ ], "tests": [ { - "description": "UpdateOne requires atomic modifiers", + "description": "UpdateMany requires atomic modifiers", "operations": [ { - "object": "collection0", "name": "updateMany", + "object": "collection0", "arguments": { "filter": { "_id": { @@ -63,7 +63,7 @@ } }, "expectError": { - "isError": true + "isClientError": true } } ], @@ -75,8 +75,8 @@ ], "outcome": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, diff --git a/tests/UnifiedSpecTests/crud/updateOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/updateOne-dots_and_dollars.json new file mode 100644 index 000000000..798d522cb --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-dots_and_dollars.json @@ -0,0 +1,412 @@ +{ + "description": "updateOne-dots_and_dollars", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {} + } + ] + } + ], + "tests": [ + { + "description": "Updating document to set top-level dollar-prefixed key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "$a": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set top-level dotted key on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$replaceWith": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$$ROOT" + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": {}, + "a.b": 1 + } + ] + } + ] + }, + { + "description": "Updating document to set dollar-prefixed key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "$a" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "$a": 1 + } + } + ] + } + ] + }, + { + "description": "Updating document to set dotted key in embedded doc on 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ] + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "foo": { + "$setField": { + "field": { + "$literal": "a.b" + }, + "value": 1, + "input": "$foo" + } + } + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ] + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "foo": { + "a.b": 1 + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json index 8c0ddbd1d..d4f1a5343 100644 --- a/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json +++ b/tests/UnifiedSpecTests/crud/updateOne-hint-clientError.json @@ -1,6 +1,6 @@ { "description": "updateOne-hint-clientError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "maxServerVersion": "3.3.99" diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json b/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json index d8a46da94..05fb03331 100644 --- a/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json +++ b/tests/UnifiedSpecTests/crud/updateOne-hint-serverError.json @@ -1,6 +1,6 @@ { "description": "updateOne-hint-serverError", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "3.4.0", diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint.json b/tests/UnifiedSpecTests/crud/updateOne-hint.json index 9277c605f..484e00757 100644 --- a/tests/UnifiedSpecTests/crud/updateOne-hint.json +++ b/tests/UnifiedSpecTests/crud/updateOne-hint.json @@ -1,6 +1,6 @@ { "description": "updateOne-hint", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.2.0" diff --git a/tests/UnifiedSpecTests/crud/updateOne-validation.json b/tests/UnifiedSpecTests/crud/updateOne-validation.json index 8336efc0d..1464642c5 100644 --- a/tests/UnifiedSpecTests/crud/updateOne-validation.json +++ b/tests/UnifiedSpecTests/crud/updateOne-validation.json @@ -1,6 +1,6 @@ { "description": "updateOne-validation", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "createEntities": [ { "client": { @@ -14,21 +14,21 @@ "database": { "id": "database0", "client": "client0", - "databaseName": "crud-v2" + "databaseName": "crud-tests" } }, { "collection": { "id": "collection0", "database": "database0", - "collectionName": "crud-v2" + "collectionName": "coll0" } } ], "initialData": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, @@ -42,8 +42,8 @@ "description": "UpdateOne requires atomic modifiers", "operations": [ { - "object": "collection0", "name": "updateOne", + "object": "collection0", "arguments": { "filter": { "_id": 1 @@ -53,7 +53,7 @@ } }, "expectError": { - "isError": true + "isClientError": true } } ], @@ -65,8 +65,8 @@ ], "outcome": [ { - "collectionName": "crud-v2", - "databaseName": "crud-v2", + "collectionName": "coll0", + "databaseName": "crud-tests", "documents": [ { "_id": 1, diff --git a/tests/UnifiedSpecTests/crud/updateWithPipelines.json b/tests/UnifiedSpecTests/crud/updateWithPipelines.json index 12ae04665..164f2f6a1 100644 --- a/tests/UnifiedSpecTests/crud/updateWithPipelines.json +++ b/tests/UnifiedSpecTests/crud/updateWithPipelines.json @@ -1,6 +1,6 @@ { "description": "updateWithPipelines", - "schemaVersion": "1.1", + "schemaVersion": "1.0", "runOnRequirements": [ { "minServerVersion": "4.1.11" From 4ee3fb3c32a32f5227c7d304eaa9a6c4f7e131b6 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 14 Jun 2021 11:33:51 -0400 Subject: [PATCH 042/321] PHPLIB-663: Update aggregate-let spec test (#833) Synced with mongodb/specifications@3a58fc612b3520030a97a1161a5651c451c40f8e --- .../UnifiedSpecTests/crud/aggregate-let.json | 283 ++++++++++++++++++ 1 file changed, 283 insertions(+) diff --git a/tests/UnifiedSpecTests/crud/aggregate-let.json b/tests/UnifiedSpecTests/crud/aggregate-let.json index f31c6ee9d..4ce8256cb 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-let.json +++ b/tests/UnifiedSpecTests/crud/aggregate-let.json @@ -23,6 +23,13 @@ "database": "database0", "collectionName": "coll0" } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1" + } } ], "initialData": [ @@ -34,6 +41,11 @@ "_id": 1 } ] + }, + { + "collectionName": "coll1", + "databaseName": "crud-tests", + "documents": [] } ], "tests": [ @@ -44,6 +56,109 @@ "minServerVersion": "5.0" } ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 0, + "x": "$$x", + "y": "$$y", + "rand": "$$rand" + } + } + ], + "let": { + "id": 1, + "x": "foo", + "y": { + "$literal": "bar" + }, + "rand": { + "$rand": {} + } + } + }, + "expectResult": [ + { + "x": "foo", + "y": "bar", + "rand": { + "$$type": "double" + } + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 0, + "x": "$$x", + "y": "$$y", + "rand": "$$rand" + } + } + ], + "let": { + "id": 1, + "x": "foo", + "y": { + "$literal": "bar" + }, + "rand": { + "$rand": {} + } + } + } + } + } + ] + } + ] + }, + { + "description": "Aggregate with let option and dollar-prefixed $literal value", + "runOnRequirements": [ + { + "minServerVersion": "5.0", + "topologies": [ + "single", + "replicaset" + ] + } + ], "operations": [ { "name": "aggregate", @@ -190,6 +305,174 @@ ] } ] + }, + { + "description": "Aggregate to collection with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll1" + } + ], + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll1" + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll1", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Aggregate to collection with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "2.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll1" + } + ], + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "unrecognized field 'let'", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll1" + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ] } ] } From 2407bc449b811fae8d9327f81c38d87805a28573 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 29 Jun 2021 10:29:49 +0200 Subject: [PATCH 043/321] PHPLIB-659 Support options for time-series collections (#829) * PHPLIB-659 Support options for time-series collections * Update wording about 5.0 support --- ...tabase-method-createCollection-option.yaml | 29 ++ src/Operation/CreateCollection.php | 20 +- tests/Operation/CreateCollectionTest.php | 8 + tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 + .../timeseries-collection.json | 255 ++++++++++++++++++ 5 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 tests/UnifiedSpecTests/collection-management/timeseries-collection.json diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 76dbf405a..7695309b3 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -35,6 +35,21 @@ pre: | ` for the collection. --- arg_name: option +name: expireAfterSeconds +type: integer +description: | + Allows specifying a TTL after which documents will be removed from a + time-series collection. + + This option is available in MongoDB 5.0+ and will result in an exception at + execution time if specified for an older server version. + + .. versionadded:: 1.9 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: flags type: integer description: | @@ -133,6 +148,20 @@ interface: phpmethod operation: ~ optional: true --- +arg_name: option +name: timeseries +type: array|object +description: | + Allows users to specify options for time-series collections. + + This option is available in MongoDB 5.0+ and will result in an exception at + execution time if specified for an older server version. + + .. versionadded:: 1.9 +interface: phpmethod +operation: ~ +optional: true +--- source: file: apiargs-MongoDBDatabase-common-option.yaml ref: typeMap diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index 98fac51d6..08d547add 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -82,6 +82,10 @@ class CreateCollection implements Executable * This is not supported for server versions < 3.4 and will result in an * exception at execution time if used. * + * * expireAfterSeconds: The TTL for documents in time series collections. + * + * This is not supported for servers versions < 5.0. + * * * flags (integer): Options for the MMAPv1 storage engine only. Must be a * bitwise combination CreateCollection::USE_POWER_OF_2_SIZES and * CreateCollection::NO_PADDING. The default is @@ -104,6 +108,10 @@ class CreateCollection implements Executable * * * storageEngine (document): Storage engine options. * + * * timeseries (document): Options for time series collections. + * + * This is not supported for servers versions < 5.0. + * * * typeMap (array): Type map for BSON deserialization. This will only be * used for the returned command result document. * @@ -139,6 +147,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); } + if (isset($options['expireAfterSeconds']) && ! is_integer($options['expireAfterSeconds'])) { + throw InvalidArgumentException::invalidType('"expireAfterSeconds" option', $options['expireAfterSeconds'], 'integer'); + } + if (isset($options['flags']) && ! is_integer($options['flags'])) { throw InvalidArgumentException::invalidType('"flags" option', $options['flags'], 'integer'); } @@ -167,6 +179,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"storageEngine" option', $options['storageEngine'], 'array or object'); } + if (isset($options['timeseries']) && ! is_array($options['timeseries']) && ! is_object($options['timeseries'])) { + throw InvalidArgumentException::invalidType('"timeseries" option', $options['timeseries'], ['array', 'object']); + } + if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); } @@ -237,13 +253,13 @@ private function createCommand() { $cmd = ['create' => $this->collectionName]; - foreach (['autoIndexId', 'capped', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) { + foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } } - foreach (['collation', 'indexOptionDefaults', 'storageEngine', 'validator'] as $option) { + foreach (['collation', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = (object) $this->options[$option]; } diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index da158eed5..c64188291 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -32,6 +32,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['collation' => $value]; } + foreach ($this->getInvalidIntegerValues() as $value) { + $options[][] = ['expireAfterSeconds' => $value]; + } + foreach ($this->getInvalidIntegerValues() as $value) { $options[][] = ['flags' => $value]; } @@ -60,6 +64,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['storageEngine' => $value]; } + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['timeseries' => $value]; + } + foreach ($this->getInvalidArrayValues() as $value) { $options[][] = ['typeMap' => $value]; } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index a27753621..7e1061ca3 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -141,6 +141,19 @@ public function provideChangeStreamsTests() return $this->provideTests(__DIR__ . '/change-streams/*.json'); } + /** + * @dataProvider provideCollectionManagementTests + */ + public function testCollectionManagement(UnifiedTestCase $test) + { + self::$runner->run($test); + } + + public function provideCollectionManagementTests() + { + return $this->provideTests(__DIR__ . '/collection-management/*.json'); + } + /** * @dataProvider provideCrudTests */ diff --git a/tests/UnifiedSpecTests/collection-management/timeseries-collection.json b/tests/UnifiedSpecTests/collection-management/timeseries-collection.json new file mode 100644 index 000000000..b5638fd36 --- /dev/null +++ b/tests/UnifiedSpecTests/collection-management/timeseries-collection.json @@ -0,0 +1,255 @@ +{ + "description": "timeseries-collection", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "ts-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "ts-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "createCollection with all options", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "expireAfterSeconds": 604800, + "timeseries": { + "timeField": "time", + "metaField": "meta", + "granularity": "minutes" + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "databaseName": "ts-tests", + "collectionName": "test" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "ts-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "expireAfterSeconds": 604800, + "timeseries": { + "timeField": "time", + "metaField": "meta", + "granularity": "minutes" + } + }, + "databaseName": "ts-tests" + } + } + ] + } + ] + }, + { + "description": "insertMany with duplicate ids", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "expireAfterSeconds": 604800, + "timeseries": { + "timeField": "time", + "metaField": "meta", + "granularity": "minutes" + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "databaseName": "ts-tests", + "collectionName": "test" + } + }, + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 1, + "time": { + "$date": { + "$numberLong": "1552949630482" + } + } + }, + { + "_id": 1, + "time": { + "$date": { + "$numberLong": "1552949630483" + } + } + } + ] + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "sort": { + "time": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "time": { + "$date": { + "$numberLong": "1552949630482" + } + } + }, + { + "_id": 1, + "time": { + "$date": { + "$numberLong": "1552949630483" + } + } + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "ts-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "expireAfterSeconds": 604800, + "timeseries": { + "timeField": "time", + "metaField": "meta", + "granularity": "minutes" + } + }, + "databaseName": "ts-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1, + "time": { + "$date": { + "$numberLong": "1552949630482" + } + } + }, + { + "_id": 1, + "time": { + "$date": { + "$numberLong": "1552949630483" + } + } + } + ] + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": {}, + "sort": { + "time": 1 + } + }, + "databaseName": "ts-tests" + } + } + ] + } + ] + } + ] +} From a295cd0fb93c757974dced9b7d5ee0996109b449 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 29 Jun 2021 10:30:50 +0200 Subject: [PATCH 044/321] PHPLIB-654 Remove deprecated terminology (#828) * Remove deprecated terminology * Update spec tests Updates spec tests to commit mongodb/specifications#6d7fd374ca14a80edabeefdd27cdd6187c43a0eb * Use ping instead of hello in docs --- .../method/MongoDBDatabase-command.txt | 27 +- src/ChangeStream.php | 6 +- tests/Database/DatabaseFunctionalTest.php | 12 +- tests/Operation/WatchFunctionalTest.php | 8 +- .../ClientSideEncryptionSpecTest.php | 2 +- tests/SpecTests/PrimaryStepDownSpecTest.php | 18 +- .../aggregate-serverErrors.json | 10 +- ...angeStreams-client.watch-serverErrors.json | 10 +- ...ngeStreams-db.coll.watch-serverErrors.json | 10 +- .../changeStreams-db.watch-serverErrors.json | 10 +- .../retryable-reads/count-serverErrors.json | 10 +- .../countDocuments-serverErrors.json | 10 +- .../distinct-serverErrors.json | 10 +- .../estimatedDocumentCount-4.9.json | 418 ++--- ...timatedDocumentCount-serverErrors-4.9.json | 1586 ++++++++--------- ...atedDocumentCount-serverErrors-pre4.9.json | 10 +- .../retryable-reads/find-serverErrors.json | 10 +- .../retryable-reads/findOne-serverErrors.json | 10 +- .../gridfs-download-serverErrors.json | 10 +- .../gridfs-downloadByName-serverErrors.json | 10 +- .../listCollectionNames-serverErrors.json | 10 +- .../listCollectionObjects-serverErrors.json | 10 +- .../listCollections-serverErrors.json | 10 +- .../listDatabaseNames-serverErrors.json | 10 +- .../listDatabaseObjects-serverErrors.json | 10 +- .../listDatabases-serverErrors.json | 10 +- .../listIndexNames-serverErrors.json | 10 +- .../listIndexes-serverErrors.json | 10 +- .../insertOne-serverErrors.json | 6 +- .../commit-retry.json | 2 +- .../SpecTests/transactions/error-labels.json | 2 +- .../transactions/mongos-recovery-token.json | 3 +- tests/SpecTests/transactions/pin-mongos.json | 3 +- .../transactions/retryable-abort.json | 6 +- .../transactions/retryable-commit.json | 6 +- tests/UnifiedSpecTests/EventObserver.php | 1 + 36 files changed, 1146 insertions(+), 1160 deletions(-) diff --git a/docs/reference/method/MongoDBDatabase-command.txt b/docs/reference/method/MongoDBDatabase-command.txt index 46b28fbee..63ddeeaa2 100644 --- a/docs/reference/method/MongoDBDatabase-command.txt +++ b/docs/reference/method/MongoDBDatabase-command.txt @@ -43,8 +43,8 @@ Errors/Exceptions Example ------- -The following example executes an :manual:`isMaster -` command, which returns a cursor with a single +The following example executes a :manual:`ping +` command, which returns a cursor with a single result document: .. code-block:: php @@ -53,7 +53,7 @@ result document: $database = (new MongoDB\Client)->test; - $cursor = $database->command(['isMaster' => 1]); + $cursor = $database->command(['ping' => 1]); var_dump($c->toArray()[0]); @@ -61,24 +61,7 @@ The output would resemble:: object(MongoDB\Model\BSONDocument)#11 (1) { ["storage":"ArrayObject":private]=> - array(8) { - ["ismaster"]=> - bool(true) - ["maxBsonObjectSize"]=> - int(16777216) - ["maxMessageSizeBytes"]=> - int(48000000) - ["maxWriteBatchSize"]=> - int(1000) - ["localTime"]=> - object(MongoDB\BSON\UTCDateTime)#3 (1) { - ["milliseconds"]=> - string(13) "1477608046464" - } - ["maxWireVersion"]=> - int(4) - ["minWireVersion"]=> - int(0) + array(1) { ["ok"]=> float(1) } @@ -94,7 +77,7 @@ multiple result documents: $database = (new MongoDB\Client)->test; - $cursor = $database->command(['isMaster' => 1]); + $cursor = $database->command(['listCollections' => 1]); var_dump($c->toArray()); diff --git a/src/ChangeStream.php b/src/ChangeStream.php index fcf16dde8..ea0de63e4 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -54,11 +54,11 @@ class ChangeStream implements Iterator 189, // PrimarySteppedDown 262, // ExceededTimeLimit 9001, // SocketException - 10107, // NotMaster + 10107, // NotPrimary 11600, // InterruptedAtShutdown 11602, // InterruptedDueToReplStateChange - 13435, // NotMasterNoSlaveOk - 13436, // NotMasterOrSecondary + 13435, // NotPrimaryNoSecondaryOk + 13436, // NotPrimaryOrSecondary 63, // StaleShardVersion 150, // StaleEpoch 13388, // StaleConfig diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 7f81e6d58..347abd9fd 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -85,7 +85,7 @@ public function getGetDatabaseName() public function testCommand() { - $command = ['isMaster' => 1]; + $command = ['ping' => 1]; $options = [ 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), ]; @@ -96,8 +96,8 @@ public function testCommand() $commandResult = current($cursor->toArray()); $this->assertCommandSucceeded($commandResult); - $this->assertObjectHasAttribute('ismaster', $commandResult); - $this->assertTrue($commandResult->ismaster); + $this->assertObjectHasAttribute('ok', $commandResult); + $this->assertSame(1, (int) $commandResult->ok); } public function testCommandDoesNotInheritReadPreference() @@ -118,7 +118,7 @@ public function testCommandDoesNotInheritReadPreference() public function testCommandAppliesTypeMapToCursor() { - $command = ['isMaster' => 1]; + $command = ['ping' => 1]; $options = [ 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), 'typeMap' => ['root' => 'array'], @@ -131,8 +131,8 @@ public function testCommandAppliesTypeMapToCursor() $this->assertCommandSucceeded($commandResult); $this->assertIsArray($commandResult); - $this->assertArrayHasKey('ismaster', $commandResult); - $this->assertTrue($commandResult['ismaster']); + $this->assertArrayHasKey('ok', $commandResult); + $this->assertSame(1, (int) $commandResult['ok']); } /** diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index 426aec4af..a5ebae68d 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -40,7 +40,7 @@ class WatchFunctionalTest extends FunctionalTestCase use SetUpTearDownTrait; const INTERRUPTED = 11601; - const NOT_MASTER = 10107; + const NOT_PRIMARY = 10107; /** @var integer */ private static $wireVersionForStartAtOperationTime = 7; @@ -1198,7 +1198,7 @@ public function testSessionFreed() /** * Prose test 3: "ChangeStream will automatically resume one time on a - * resumable error (including not master) with the initial pipeline and + * resumable error (including not primary) with the initial pipeline and * options, except for the addition/update of a resumeToken." */ public function testResumeRepeatsOriginalPipelineAndOptions() @@ -1212,7 +1212,7 @@ public function testResumeRepeatsOriginalPipelineAndOptions() 'mode' => ['times' => 1], 'data' => [ 'failCommands' => ['getMore'], - 'errorCode' => self::NOT_MASTER, + 'errorCode' => self::NOT_PRIMARY, 'errorLabels' => ['ResumableChangeStreamError'], ], ]); @@ -1568,7 +1568,7 @@ private function forceChangeStreamResume() 'mode' => ['times' => 1], 'data' => [ 'failCommands' => ['getMore'], - 'errorCode' => self::NOT_MASTER, + 'errorCode' => self::NOT_PRIMARY, 'errorLabels' => ['ResumableChangeStreamError'], ], ]); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 43b627240..2853ec26c 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -793,7 +793,7 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption() $clientMongocryptd = static::createTestClient('mongodb://localhost:27021'); $this->expectException(ConnectionTimeoutException::class); - $clientMongocryptd->selectDatabase('db')->command(['isMaster' => true]); + $clientMongocryptd->selectDatabase('db')->command(['ping' => 1]); } /** diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php index c496444aa..135e3deb5 100644 --- a/tests/SpecTests/PrimaryStepDownSpecTest.php +++ b/tests/SpecTests/PrimaryStepDownSpecTest.php @@ -25,7 +25,7 @@ class PrimaryStepDownSpecTest extends FunctionalTestCase use SetUpTearDownTrait; const INTERRUPTED_AT_SHUTDOWN = 11600; - const NOT_MASTER = 10107; + const NOT_PRIMARY = 10107; const SHUTDOWN_IN_PROGRESS = 91; /** @var Client */ @@ -47,7 +47,7 @@ private function doSetUp() /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id10 */ - public function testNotMasterKeepsConnectionPool() + public function testNotPrimaryKeepsConnectionPool() { $runOn = [(object) ['minServerVersion' => '4.1.11', 'topology' => [self::TOPOLOGY_REPLICASET]]]; $this->checkServerRequirements($runOn); @@ -58,7 +58,7 @@ public function testNotMasterKeepsConnectionPool() 'mode' => ['times' => 1], 'data' => [ 'failCommands' => ['insert'], - 'errorCode' => self::NOT_MASTER, + 'errorCode' => self::NOT_PRIMARY, ], ]); @@ -69,7 +69,7 @@ public function testNotMasterKeepsConnectionPool() $this->insertDocuments(1); } catch (BulkWriteException $e) { // Verify that the insert failed with an operation failure with 10107 code. - $this->assertSame(self::NOT_MASTER, $e->getCode()); + $this->assertSame(self::NOT_PRIMARY, $e->getCode()); } // Execute an insert into the test collection of a {test: 1} document and verify that it succeeds. @@ -83,7 +83,7 @@ public function testNotMasterKeepsConnectionPool() /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id11 */ - public function testNotMasterResetConnectionPool() + public function testNotPrimaryResetConnectionPool() { $runOn = [(object) ['minServerVersion' => '4.0.0', 'maxServerVersion' => '4.0.999', 'topology' => [self::TOPOLOGY_REPLICASET]]]; $this->checkServerRequirements($runOn); @@ -94,7 +94,7 @@ public function testNotMasterResetConnectionPool() 'mode' => ['times' => 1], 'data' => [ 'failCommands' => ['insert'], - 'errorCode' => self::NOT_MASTER, + 'errorCode' => self::NOT_PRIMARY, ], ]); @@ -105,7 +105,7 @@ public function testNotMasterResetConnectionPool() $this->insertDocuments(1); } catch (BulkWriteException $e) { // Verify that the insert failed with an operation failure with 10107 code. - $this->assertSame(self::NOT_MASTER, $e->getCode()); + $this->assertSame(self::NOT_PRIMARY, $e->getCode()); } // Verify that the connection pool has been cleared @@ -248,7 +248,7 @@ function ($event) use (&$events) { $this->assertSame($totalConnectionsCreated, $this->getTotalConnectionsCreated($cursor->getServer())); // Wait to allow primary election to complete and prevent subsequent test failures - $this->waitForMasterReelection(); + $this->waitForPrimaryReelection(); } private function insertDocuments($count) @@ -290,7 +290,7 @@ private function getTotalConnectionsCreated(Server $server = null) throw new UnexpectedValueException('Could not determine number of total connections'); } - private function waitForMasterReelection() + private function waitForPrimaryReelection() { try { $this->insertDocuments(1); diff --git a/tests/SpecTests/retryable-reads/aggregate-serverErrors.json b/tests/SpecTests/retryable-reads/aggregate-serverErrors.json index 04208bc95..f6197cc9f 100644 --- a/tests/SpecTests/retryable-reads/aggregate-serverErrors.json +++ b/tests/SpecTests/retryable-reads/aggregate-serverErrors.json @@ -218,7 +218,7 @@ ] }, { - "description": "Aggregate succeeds after NotMaster", + "description": "Aggregate succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -311,7 +311,7 @@ ] }, { - "description": "Aggregate succeeds after NotMasterNoSlaveOk", + "description": "Aggregate succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -404,7 +404,7 @@ ] }, { - "description": "Aggregate succeeds after NotMasterOrSecondary", + "description": "Aggregate succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1055,7 +1055,7 @@ ] }, { - "description": "Aggregate fails after two NotMaster errors", + "description": "Aggregate fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -1139,7 +1139,7 @@ ] }, { - "description": "Aggregate fails after NotMaster when retryReads is false", + "description": "Aggregate fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json b/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json index cf6c230ec..f67ee8d30 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json +++ b/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json @@ -141,7 +141,7 @@ ] }, { - "description": "client.watch succeeds after NotMaster", + "description": "client.watch succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -196,7 +196,7 @@ ] }, { - "description": "client.watch succeeds after NotMasterNoSlaveOk", + "description": "client.watch succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -251,7 +251,7 @@ ] }, { - "description": "client.watch succeeds after NotMasterOrSecondary", + "description": "client.watch succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -636,7 +636,7 @@ ] }, { - "description": "client.watch fails after two NotMaster errors", + "description": "client.watch fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -692,7 +692,7 @@ ] }, { - "description": "client.watch fails after NotMaster when retryReads is false", + "description": "client.watch fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json b/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json index eb7df1e26..63514f6a8 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json +++ b/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json @@ -133,7 +133,7 @@ ] }, { - "description": "db.coll.watch succeeds after NotMaster", + "description": "db.coll.watch succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -184,7 +184,7 @@ ] }, { - "description": "db.coll.watch succeeds after NotMasterNoSlaveOk", + "description": "db.coll.watch succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -235,7 +235,7 @@ ] }, { - "description": "db.coll.watch succeeds after NotMasterOrSecondary", + "description": "db.coll.watch succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -592,7 +592,7 @@ ] }, { - "description": "db.coll.watch fails after two NotMaster errors", + "description": "db.coll.watch fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -644,7 +644,7 @@ ] }, { - "description": "db.coll.watch fails after NotMaster when retryReads is false", + "description": "db.coll.watch fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json b/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json index e070f56a0..8d1624240 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json +++ b/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json @@ -133,7 +133,7 @@ ] }, { - "description": "db.watch succeeds after NotMaster", + "description": "db.watch succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -184,7 +184,7 @@ ] }, { - "description": "db.watch succeeds after NotMasterNoSlaveOk", + "description": "db.watch succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -235,7 +235,7 @@ ] }, { - "description": "db.watch succeeds after NotMasterOrSecondary", + "description": "db.watch succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -592,7 +592,7 @@ ] }, { - "description": "db.watch fails after two NotMaster errors", + "description": "db.watch fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -644,7 +644,7 @@ ] }, { - "description": "db.watch fails after NotMaster when retryReads is false", + "description": "db.watch fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/count-serverErrors.json b/tests/SpecTests/retryable-reads/count-serverErrors.json index 839680fe5..1de695eb8 100644 --- a/tests/SpecTests/retryable-reads/count-serverErrors.json +++ b/tests/SpecTests/retryable-reads/count-serverErrors.json @@ -114,7 +114,7 @@ ] }, { - "description": "Count succeeds after NotMaster", + "description": "Count succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -157,7 +157,7 @@ ] }, { - "description": "Count succeeds after NotMasterNoSlaveOk", + "description": "Count succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -200,7 +200,7 @@ ] }, { - "description": "Count succeeds after NotMasterOrSecondary", + "description": "Count succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -501,7 +501,7 @@ ] }, { - "description": "Count fails after two NotMaster errors", + "description": "Count fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -544,7 +544,7 @@ ] }, { - "description": "Count fails after NotMaster when retryReads is false", + "description": "Count fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json b/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json index f45eadfa0..8e7a1b58e 100644 --- a/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json +++ b/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json @@ -166,7 +166,7 @@ ] }, { - "description": "CountDocuments succeeds after NotMaster", + "description": "CountDocuments succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -235,7 +235,7 @@ ] }, { - "description": "CountDocuments succeeds after NotMasterNoSlaveOk", + "description": "CountDocuments succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -304,7 +304,7 @@ ] }, { - "description": "CountDocuments succeeds after NotMasterOrSecondary", + "description": "CountDocuments succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -787,7 +787,7 @@ ] }, { - "description": "CountDocuments fails after two NotMaster errors", + "description": "CountDocuments fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -856,7 +856,7 @@ ] }, { - "description": "CountDocuments fails after NotMaster when retryReads is false", + "description": "CountDocuments fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/distinct-serverErrors.json b/tests/SpecTests/retryable-reads/distinct-serverErrors.json index 50fd6a550..c168b37ec 100644 --- a/tests/SpecTests/retryable-reads/distinct-serverErrors.json +++ b/tests/SpecTests/retryable-reads/distinct-serverErrors.json @@ -158,7 +158,7 @@ ] }, { - "description": "Distinct succeeds after NotMaster", + "description": "Distinct succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -221,7 +221,7 @@ ] }, { - "description": "Distinct succeeds after NotMasterNoSlaveOk", + "description": "Distinct succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -284,7 +284,7 @@ ] }, { - "description": "Distinct succeeds after NotMasterOrSecondary", + "description": "Distinct succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -725,7 +725,7 @@ ] }, { - "description": "Distinct fails after two NotMaster errors", + "description": "Distinct fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -785,7 +785,7 @@ ] }, { - "description": "Distinct fails after NotMaster when retryReads is false", + "description": "Distinct fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json index 7925bd5ef..a4c46fc07 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json @@ -1,246 +1,246 @@ { - "runOn": [ + "runOn": [ + { + "minServerVersion": "4.9.0" + } + ], + "database_name": "retryable-reads-tests", + "collection_name": "coll", + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "EstimatedDocumentCount succeeds on first attempt", + "operations": [ { - "minServerVersion": "4.9.0" + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 } - ], - "database_name": "retryable-reads-tests", - "collection_name": "coll", - "data": [ + ], + "expectations": [ { - "_id": 1, - "x": 11 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds on second attempt", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + }, + "operations": [ { - "_id": 2, - "x": 22 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 } - ], - "tests": [ + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds on first attempt", - "operations": [ + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ + "$collStats": { + "count": {} + } + }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } }, { - "description": "EstimatedDocumentCount succeeds on second attempt", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails on first attempt", + "clientOptions": { + "retryReads": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + }, + "operations": [ { - "description": "EstimatedDocumentCount fails on first attempt", - "clientOptions": { - "retryReads": false - }, - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } - }, - "operations": [ + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ + "$collStats": { + "count": {} + } + }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails on second attempt", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + }, + "operations": [ { - "description": "EstimatedDocumentCount fails on second attempt", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 2 + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } } - ], - "expectations": [ + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } } - ] + ] + } + ] } diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json index 1e1adfb92..756b02b3a 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json @@ -1,911 +1,911 @@ { - "runOn": [ - { - "minServerVersion": "4.9.0" - } - ], - "database_name": "retryable-reads-tests", - "collection_name": "coll", - "data": [ - { - "_id": 1, - "x": 11 + "runOn": [ + { + "minServerVersion": "4.9.0" + } + ], + "database_name": "retryable-reads-tests", + "collection_name": "coll", + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "tests": [ + { + "description": "EstimatedDocumentCount succeeds after InterruptedAtShutdown", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 11600 + } + }, + "operations": [ { - "_id": 2, - "x": 22 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 } - ], - "tests": [ + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds after InterruptedAtShutdown", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 11600 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after InterruptedDueToReplStateChange", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 11602 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds after InterruptedDueToReplStateChange", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 11602 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NotWritablePrimary", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 10107 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds after NotMaster", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 10107 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NotPrimaryNoSecondaryOk", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 13435 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount succeeds after NotMasterNoSlaveOk", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 13435 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NotPrimaryOrSecondary", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 13436 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds after NotMasterOrSecondary", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 13436 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after PrimarySteppedDown", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 189 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds after PrimarySteppedDown", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 189 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after ShutdownInProgress", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 91 + } + }, + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ { - "description": "EstimatedDocumentCount succeeds after ShutdownInProgress", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 91 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after HostNotFound", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 7 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount succeeds after HostNotFound", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 7 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after HostUnreachable", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 6 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount succeeds after HostUnreachable", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 6 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after NetworkTimeout", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 89 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount succeeds after NetworkTimeout", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 89 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount succeeds after SocketException", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 9001 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount succeeds after SocketException", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "name": "estimatedDocumentCount", + "object": "collection", + "result": 2 + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 9001 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails after two NotWritablePrimary errors", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 10107 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount fails after two NotMaster errors", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 2 + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 10107 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } + } + ] + }, + "database_name": "retryable-reads-tests" + } + }, + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } + } + ] + }, + { + "description": "EstimatedDocumentCount fails after NotWritablePrimary when retryReads is false", + "clientOptions": { + "retryReads": false + }, + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 }, + "data": { + "failCommands": [ + "aggregate" + ], + "errorCode": 10107 + } + }, + "operations": [ { - "description": "EstimatedDocumentCount fails after NotMaster when retryReads is false", - "clientOptions": { - "retryReads": false - }, - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 + "name": "estimatedDocumentCount", + "object": "collection", + "error": true + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "coll", + "pipeline": [ + { + "$collStats": { + "count": {} + } }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 10107 - } - }, - "operations": [ { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" + "$group": { + "_id": 1, + "n": { + "$sum": "$count" } + } } - ] + ] + }, + "database_name": "retryable-reads-tests" + } } - ] -} \ No newline at end of file + ] + } + ] +} diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json index c11e609cd..0b9a2615d 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json @@ -110,7 +110,7 @@ ] }, { - "description": "EstimatedDocumentCount succeeds after NotMaster", + "description": "EstimatedDocumentCount succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -150,7 +150,7 @@ ] }, { - "description": "EstimatedDocumentCount succeeds after NotMasterNoSlaveOk", + "description": "EstimatedDocumentCount succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -190,7 +190,7 @@ ] }, { - "description": "EstimatedDocumentCount succeeds after NotMasterOrSecondary", + "description": "EstimatedDocumentCount succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -470,7 +470,7 @@ ] }, { - "description": "EstimatedDocumentCount fails after two NotMaster errors", + "description": "EstimatedDocumentCount fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -510,7 +510,7 @@ ] }, { - "description": "EstimatedDocumentCount fails after NotMaster when retryReads is false", + "description": "EstimatedDocumentCount fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/find-serverErrors.json b/tests/SpecTests/retryable-reads/find-serverErrors.json index 44ecf34d2..3d1cfa456 100644 --- a/tests/SpecTests/retryable-reads/find-serverErrors.json +++ b/tests/SpecTests/retryable-reads/find-serverErrors.json @@ -188,7 +188,7 @@ ] }, { - "description": "Find succeeds after NotMaster", + "description": "Find succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -262,7 +262,7 @@ ] }, { - "description": "Find succeeds after NotMasterNoSlaveOk", + "description": "Find succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -336,7 +336,7 @@ ] }, { - "description": "Find succeeds after NotMasterOrSecondary", + "description": "Find succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -854,7 +854,7 @@ ] }, { - "description": "Find fails after two NotMaster errors", + "description": "Find fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -911,7 +911,7 @@ ] }, { - "description": "Find fails after NotMaster when retryReads is false", + "description": "Find fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/findOne-serverErrors.json b/tests/SpecTests/retryable-reads/findOne-serverErrors.json index b8229483d..161dc42f3 100644 --- a/tests/SpecTests/retryable-reads/findOne-serverErrors.json +++ b/tests/SpecTests/retryable-reads/findOne-serverErrors.json @@ -148,7 +148,7 @@ ] }, { - "description": "FindOne succeeds after NotMaster", + "description": "FindOne succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -202,7 +202,7 @@ ] }, { - "description": "FindOne succeeds after NotMasterNoSlaveOk", + "description": "FindOne succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -256,7 +256,7 @@ ] }, { - "description": "FindOne succeeds after NotMasterOrSecondary", + "description": "FindOne succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -634,7 +634,7 @@ ] }, { - "description": "FindOne fails after two NotMaster errors", + "description": "FindOne fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -685,7 +685,7 @@ ] }, { - "description": "FindOne fails after NotMaster when retryReads is false", + "description": "FindOne fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json b/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json index 84e50e370..af091d679 100644 --- a/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json +++ b/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json @@ -191,7 +191,7 @@ ] }, { - "description": "Download succeeds after NotMaster", + "description": "Download succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -261,7 +261,7 @@ ] }, { - "description": "Download succeeds after NotMasterNoSlaveOk", + "description": "Download succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -331,7 +331,7 @@ ] }, { - "description": "Download succeeds after NotMasterOrSecondary", + "description": "Download succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -821,7 +821,7 @@ ] }, { - "description": "Download fails after two NotMaster errors", + "description": "Download fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -876,7 +876,7 @@ ] }, { - "description": "Download fails after NotMaster when retryReads is false", + "description": "Download fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json b/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json index de439ce4b..61e3a5947 100644 --- a/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json +++ b/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json @@ -179,7 +179,7 @@ ] }, { - "description": "DownloadByName succeeds after NotMaster", + "description": "DownloadByName succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -243,7 +243,7 @@ ] }, { - "description": "DownloadByName succeeds after NotMasterNoSlaveOk", + "description": "DownloadByName succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -307,7 +307,7 @@ ] }, { - "description": "DownloadByName succeeds after NotMasterOrSecondary", + "description": "DownloadByName succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -755,7 +755,7 @@ ] }, { - "description": "DownloadByName fails after two NotMaster errors", + "description": "DownloadByName fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -804,7 +804,7 @@ ] }, { - "description": "DownloadByName fails after NotMaster when retryReads is false", + "description": "DownloadByName fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json b/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json index 27c13d630..a07e746a5 100644 --- a/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json @@ -93,7 +93,7 @@ ] }, { - "description": "ListCollectionNames succeeds after NotMaster", + "description": "ListCollectionNames succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -130,7 +130,7 @@ ] }, { - "description": "ListCollectionNames succeeds after NotMasterNoSlaveOk", + "description": "ListCollectionNames succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -167,7 +167,7 @@ ] }, { - "description": "ListCollectionNames succeeds after NotMasterOrSecondary", + "description": "ListCollectionNames succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -426,7 +426,7 @@ ] }, { - "description": "ListCollectionNames fails after two NotMaster errors", + "description": "ListCollectionNames fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -464,7 +464,7 @@ ] }, { - "description": "ListCollectionNames fails after NotMaster when retryReads is false", + "description": "ListCollectionNames fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json b/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json index 3922713df..c2d4358fb 100644 --- a/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json @@ -93,7 +93,7 @@ ] }, { - "description": "ListCollectionObjects succeeds after NotMaster", + "description": "ListCollectionObjects succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -130,7 +130,7 @@ ] }, { - "description": "ListCollectionObjects succeeds after NotMasterNoSlaveOk", + "description": "ListCollectionObjects succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -167,7 +167,7 @@ ] }, { - "description": "ListCollectionObjects succeeds after NotMasterOrSecondary", + "description": "ListCollectionObjects succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -426,7 +426,7 @@ ] }, { - "description": "ListCollectionObjects fails after two NotMaster errors", + "description": "ListCollectionObjects fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -464,7 +464,7 @@ ] }, { - "description": "ListCollectionObjects fails after NotMaster when retryReads is false", + "description": "ListCollectionObjects fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listCollections-serverErrors.json b/tests/SpecTests/retryable-reads/listCollections-serverErrors.json index 6972073b1..f749c8c27 100644 --- a/tests/SpecTests/retryable-reads/listCollections-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listCollections-serverErrors.json @@ -93,7 +93,7 @@ ] }, { - "description": "ListCollections succeeds after NotMaster", + "description": "ListCollections succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -130,7 +130,7 @@ ] }, { - "description": "ListCollections succeeds after NotMasterNoSlaveOk", + "description": "ListCollections succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -167,7 +167,7 @@ ] }, { - "description": "ListCollections succeeds after NotMasterOrSecondary", + "description": "ListCollections succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -426,7 +426,7 @@ ] }, { - "description": "ListCollections fails after two NotMaster errors", + "description": "ListCollections fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -464,7 +464,7 @@ ] }, { - "description": "ListCollections fails after NotMaster when retryReads is false", + "description": "ListCollections fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json b/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json index 11faf58bf..959d70fb3 100644 --- a/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json @@ -93,7 +93,7 @@ ] }, { - "description": "ListDatabaseNames succeeds after NotMaster", + "description": "ListDatabaseNames succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -130,7 +130,7 @@ ] }, { - "description": "ListDatabaseNames succeeds after NotMasterNoSlaveOk", + "description": "ListDatabaseNames succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -167,7 +167,7 @@ ] }, { - "description": "ListDatabaseNames succeeds after NotMasterOrSecondary", + "description": "ListDatabaseNames succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -426,7 +426,7 @@ ] }, { - "description": "ListDatabaseNames fails after two NotMaster errors", + "description": "ListDatabaseNames fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -464,7 +464,7 @@ ] }, { - "description": "ListDatabaseNames fails after NotMaster when retryReads is false", + "description": "ListDatabaseNames fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json b/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json index 38082f2e2..6b95b421a 100644 --- a/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json @@ -93,7 +93,7 @@ ] }, { - "description": "ListDatabaseObjects succeeds after NotMaster", + "description": "ListDatabaseObjects succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -130,7 +130,7 @@ ] }, { - "description": "ListDatabaseObjects succeeds after NotMasterNoSlaveOk", + "description": "ListDatabaseObjects succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -167,7 +167,7 @@ ] }, { - "description": "ListDatabaseObjects succeeds after NotMasterOrSecondary", + "description": "ListDatabaseObjects succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -426,7 +426,7 @@ ] }, { - "description": "ListDatabaseObjects fails after two NotMaster errors", + "description": "ListDatabaseObjects fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -464,7 +464,7 @@ ] }, { - "description": "ListDatabaseObjects fails after NotMaster when retryReads is false", + "description": "ListDatabaseObjects fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json b/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json index 4047f749f..1393f5f89 100644 --- a/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json @@ -93,7 +93,7 @@ ] }, { - "description": "ListDatabases succeeds after NotMaster", + "description": "ListDatabases succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -130,7 +130,7 @@ ] }, { - "description": "ListDatabases succeeds after NotMasterNoSlaveOk", + "description": "ListDatabases succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -167,7 +167,7 @@ ] }, { - "description": "ListDatabases succeeds after NotMasterOrSecondary", + "description": "ListDatabases succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -426,7 +426,7 @@ ] }, { - "description": "ListDatabases fails after two NotMaster errors", + "description": "ListDatabases fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -464,7 +464,7 @@ ] }, { - "description": "ListDatabases fails after NotMaster when retryReads is false", + "description": "ListDatabases fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json b/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json index 1a9ba83bc..04d60f100 100644 --- a/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json @@ -97,7 +97,7 @@ ] }, { - "description": "ListIndexNames succeeds after NotMaster", + "description": "ListIndexNames succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -136,7 +136,7 @@ ] }, { - "description": "ListIndexNames succeeds after NotMasterNoSlaveOk", + "description": "ListIndexNames succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -175,7 +175,7 @@ ] }, { - "description": "ListIndexNames succeeds after NotMasterOrSecondary", + "description": "ListIndexNames succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -448,7 +448,7 @@ ] }, { - "description": "ListIndexNames fails after two NotMaster errors", + "description": "ListIndexNames fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -488,7 +488,7 @@ ] }, { - "description": "ListIndexNames fails after NotMaster when retryReads is false", + "description": "ListIndexNames fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json b/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json index 16b61d535..ccf385c5b 100644 --- a/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json @@ -97,7 +97,7 @@ ] }, { - "description": "ListIndexes succeeds after NotMaster", + "description": "ListIndexes succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -136,7 +136,7 @@ ] }, { - "description": "ListIndexes succeeds after NotMasterNoSlaveOk", + "description": "ListIndexes succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -175,7 +175,7 @@ ] }, { - "description": "ListIndexes succeeds after NotMasterOrSecondary", + "description": "ListIndexes succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -448,7 +448,7 @@ ] }, { - "description": "ListIndexes fails after two NotMaster errors", + "description": "ListIndexes fails after two NotWritablePrimary errors", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -488,7 +488,7 @@ ] }, { - "description": "ListIndexes fails after NotMaster when retryReads is false", + "description": "ListIndexes fails after NotWritablePrimary when retryReads is false", "clientOptions": { "retryReads": false }, diff --git a/tests/SpecTests/retryable-writes/insertOne-serverErrors.json b/tests/SpecTests/retryable-writes/insertOne-serverErrors.json index cb1e6f826..fda82dabb 100644 --- a/tests/SpecTests/retryable-writes/insertOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/insertOne-serverErrors.json @@ -117,7 +117,7 @@ } }, { - "description": "InsertOne succeeds after NotMaster", + "description": "InsertOne succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -166,7 +166,7 @@ } }, { - "description": "InsertOne succeeds after NotMasterOrSecondary", + "description": "InsertOne succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -215,7 +215,7 @@ } }, { - "description": "InsertOne succeeds after NotMasterNoSlaveOk", + "description": "InsertOne succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { diff --git a/tests/SpecTests/transactions-convenient-api/commit-retry.json b/tests/SpecTests/transactions-convenient-api/commit-retry.json index 312116253..02e38460d 100644 --- a/tests/SpecTests/transactions-convenient-api/commit-retry.json +++ b/tests/SpecTests/transactions-convenient-api/commit-retry.json @@ -293,7 +293,7 @@ } }, { - "description": "commit is retried after commitTransaction UnknownTransactionCommitResult (NotMaster)", + "description": "commit is retried after commitTransaction UnknownTransactionCommitResult (NotWritablePrimary)", "failPoint": { "configureFailPoint": "failCommand", "mode": { diff --git a/tests/SpecTests/transactions/error-labels.json b/tests/SpecTests/transactions/error-labels.json index 2d3eed3cc..c008a7c08 100644 --- a/tests/SpecTests/transactions/error-labels.json +++ b/tests/SpecTests/transactions/error-labels.json @@ -102,7 +102,7 @@ } }, { - "description": "NotMaster errors contain transient label", + "description": "NotWritablePrimary errors contain transient label", "failPoint": { "configureFailPoint": "failCommand", "mode": { diff --git a/tests/SpecTests/transactions/mongos-recovery-token.json b/tests/SpecTests/transactions/mongos-recovery-token.json index 35ef45a03..cd0a3c7cd 100644 --- a/tests/SpecTests/transactions/mongos-recovery-token.json +++ b/tests/SpecTests/transactions/mongos-recovery-token.json @@ -306,7 +306,8 @@ "data": { "failCommands": [ "commitTransaction", - "isMaster" + "isMaster", + "hello" ], "closeConnection": true } diff --git a/tests/SpecTests/transactions/pin-mongos.json b/tests/SpecTests/transactions/pin-mongos.json index 8e9d049d0..e0f3a880b 100644 --- a/tests/SpecTests/transactions/pin-mongos.json +++ b/tests/SpecTests/transactions/pin-mongos.json @@ -1106,7 +1106,8 @@ "data": { "failCommands": [ "insert", - "isMaster" + "isMaster", + "hello" ], "closeConnection": true } diff --git a/tests/SpecTests/transactions/retryable-abort.json b/tests/SpecTests/transactions/retryable-abort.json index 5a3aaa7bf..b712e8086 100644 --- a/tests/SpecTests/transactions/retryable-abort.json +++ b/tests/SpecTests/transactions/retryable-abort.json @@ -402,7 +402,7 @@ } }, { - "description": "abortTransaction succeeds after NotMaster", + "description": "abortTransaction succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -506,7 +506,7 @@ } }, { - "description": "abortTransaction succeeds after NotMasterOrSecondary", + "description": "abortTransaction succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -610,7 +610,7 @@ } }, { - "description": "abortTransaction succeeds after NotMasterNoSlaveOk", + "description": "abortTransaction succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { diff --git a/tests/SpecTests/transactions/retryable-commit.json b/tests/SpecTests/transactions/retryable-commit.json index 4895c6e0c..d83a1d9f5 100644 --- a/tests/SpecTests/transactions/retryable-commit.json +++ b/tests/SpecTests/transactions/retryable-commit.json @@ -624,7 +624,7 @@ } }, { - "description": "commitTransaction succeeds after NotMaster", + "description": "commitTransaction succeeds after NotWritablePrimary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -735,7 +735,7 @@ } }, { - "description": "commitTransaction succeeds after NotMasterOrSecondary", + "description": "commitTransaction succeeds after NotPrimaryOrSecondary", "failPoint": { "configureFailPoint": "failCommand", "mode": { @@ -846,7 +846,7 @@ } }, { - "description": "commitTransaction succeeds after NotMasterNoSlaveOk", + "description": "commitTransaction succeeds after NotPrimaryNoSecondaryOk", "failPoint": { "configureFailPoint": "failCommand", "mode": { diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index 011e2cee0..19c86c19a 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -52,6 +52,7 @@ final class EventObserver implements CommandSubscriber 'copydbsaslstart', 'copydb', 'isMaster', + 'hello', ]; /** @var array */ From ea9853af30c3eb899745c4a67dfec21932a37c53 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 29 Jun 2021 10:43:59 +0200 Subject: [PATCH 045/321] Fix failing transaction spec tests (#835) These tests will be fixed with PHPLIB-665 which is currently being worked on. Until then, we can skip these tests. --- tests/SpecTests/TransactionsSpecTest.php | 2 ++ tests/UnifiedSpecTests/UnifiedSpecTest.php | 1 + 2 files changed, 3 insertions(+) diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 0f8136215..0241d2e95 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -39,6 +39,8 @@ class TransactionsSpecTest extends FunctionalTestCase 'transactions/mongos-recovery-token: commitTransaction retry fails on new mongos' => 'isMaster failpoints cannot be disabled', 'transactions/pin-mongos: remain pinned after non-transient error on commit' => 'Blocked on SPEC-1320', 'transactions/pin-mongos: unpin after transient error within a transaction and commit' => 'isMaster failpoints cannot be disabled', + 'transactions/errors-client: Client side error in command starting transaction' => 'PHPLIB-665', + 'transactions/errors-client: Client side error when transaction is in progress' => 'PHPLIB-665', ]; private function doSetUp() diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 7e1061ca3..42725523c 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -105,6 +105,7 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/updateOne-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', 'crud/updateOne-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', 'crud/updateOne-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', + 'valid-pass/poc-transactions: Client side error in command starting transaction' => 'PHPLIB-665', ]; /** @var UnifiedTestRunner */ From 94f7ce08139d28bd43ca15b026ab91b5eafebc9c Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 1 Jul 2021 16:09:11 +0200 Subject: [PATCH 046/321] PHPLIB-589 Drop support for PHP 7.0 (#836) * Drop support for PHP 7.0 * Remove usage of SetupTeardownTrait --- .evergreen/config.yml | 8 ++------ .evergreen/install-dependencies.sh | 4 ---- composer.json | 2 +- tests/ClientFunctionalTest.php | 5 +---- tests/Collection/CrudSpecFunctionalTest.php | 5 +---- tests/Collection/FunctionalTestCase.php | 7 ++----- tests/Database/FunctionalTestCase.php | 5 +---- tests/DocumentationExamplesTest.php | 7 ++----- tests/FunctionalTestCase.php | 7 ++----- tests/GridFS/FunctionalTestCase.php | 5 +---- tests/GridFS/ReadableStreamFunctionalTest.php | 5 +---- tests/GridFS/StreamWrapperFunctionalTest.php | 5 +---- tests/GridFS/WritableStreamFunctionalTest.php | 5 +---- tests/Model/ChangeStreamIteratorTest.php | 5 +---- tests/Model/IndexInfoFunctionalTest.php | 7 ++----- tests/Operation/BulkWriteFunctionalTest.php | 5 +---- tests/Operation/DeleteFunctionalTest.php | 5 +---- tests/Operation/FunctionalTestCase.php | 7 ++----- tests/Operation/InsertManyFunctionalTest.php | 5 +---- tests/Operation/InsertOneFunctionalTest.php | 5 +---- tests/Operation/UpdateFunctionalTest.php | 5 +---- tests/Operation/WatchFunctionalTest.php | 5 +---- tests/SpecTests/AtlasDataLakeSpecTest.php | 5 +---- tests/SpecTests/ClientSideEncryptionSpecTest.php | 5 +---- tests/SpecTests/FunctionalTestCase.php | 7 ++----- tests/SpecTests/PrimaryStepDownSpecTest.php | 5 +---- tests/SpecTests/TransactionsSpecTest.php | 7 ++----- tests/UnifiedSpecTests/UnifiedSpecTest.php | 7 ++----- 28 files changed, 36 insertions(+), 119 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 3b9b59268..0cbdb4d34 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -400,10 +400,6 @@ axes: display_name: "7.1" variables: PHP_VERSION: "7.1.31" - - id: "7.0" - display_name: "7.0" - variables: - PHP_VERSION: "7.0.32" - id: php-edge-versions display_name: PHP Version @@ -413,9 +409,9 @@ axes: variables: PHP_VERSION: "7.4.7" - id: "oldest-supported" - display_name: "7.0" + display_name: "7.1" variables: - PHP_VERSION: "7.0.32" + PHP_VERSION: "7.1.31" - id: versions display_name: MongoDB Version diff --git a/.evergreen/install-dependencies.sh b/.evergreen/install-dependencies.sh index 765b4b32c..587558c7c 100644 --- a/.evergreen/install-dependencies.sh +++ b/.evergreen/install-dependencies.sh @@ -29,10 +29,6 @@ set_php_version () install_extension () { - # Workaround to get PECL running on PHP 7.0 - export PHP_PEAR_PHP_BIN=${PHP_PATH}/bin/php - export PHP_PEAR_INSTALL_DIR=${PHP_PATH}/lib/php - rm -f ${PHP_PATH}/lib/php.ini if [ "x${EXTENSION_BRANCH}" != "x" ] || [ "x${EXTENSION_REPO}" != "x" ]; then diff --git a/composer.json b/composer.json index 2953ebba7..18655b83e 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ { "name": "Jeremy Mikola", "email": "jmikola@gmail.com" } ], "require": { - "php": "^7.0 || ^8.0", + "php": "^7.1 || ^8.0", "ext-hash": "*", "ext-json": "*", "ext-mongodb": "^1.10.0", diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index ef07ab679..0e9a29235 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -8,7 +8,6 @@ use MongoDB\Driver\Session; use MongoDB\Model\DatabaseInfo; use MongoDB\Model\DatabaseInfoIterator; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function call_user_func; use function is_callable; use function sprintf; @@ -19,12 +18,10 @@ */ class ClientFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Client */ private $client; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index 640bfa0a3..6cfd608ec 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -14,7 +14,6 @@ use MongoDB\UpdateResult; use MultipleIterator; use PHPUnit_Framework_SkippedTestError; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function array_diff_key; use function array_key_exists; use function array_map; @@ -36,12 +35,10 @@ */ class CrudSpecFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $expectedCollection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Collection/FunctionalTestCase.php b/tests/Collection/FunctionalTestCase.php index 1735b3ec8..7202e7d19 100644 --- a/tests/Collection/FunctionalTestCase.php +++ b/tests/Collection/FunctionalTestCase.php @@ -4,19 +4,16 @@ use MongoDB\Collection; use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; /** * Base class for Collection functional tests. */ abstract class FunctionalTestCase extends BaseFunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ protected $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); @@ -25,7 +22,7 @@ private function doSetUp() $this->dropCollection(); } - private function doTearDown() + public function tearDown() : void { if ($this->hasFailed()) { return; diff --git a/tests/Database/FunctionalTestCase.php b/tests/Database/FunctionalTestCase.php index 186df2239..e3a4c48aa 100644 --- a/tests/Database/FunctionalTestCase.php +++ b/tests/Database/FunctionalTestCase.php @@ -4,19 +4,16 @@ use MongoDB\Database; use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; /** * Base class for Database functional tests. */ abstract class FunctionalTestCase extends BaseFunctionalTestCase { - use SetUpTearDownTrait; - /** @var Database */ protected $database; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 9974a6751..008201189 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -9,7 +9,6 @@ use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function in_array; use function ob_end_clean; use function ob_start; @@ -25,16 +24,14 @@ */ class DocumentationExamplesTest extends FunctionalTestCase { - use SetUpTearDownTrait; - - private function doSetUp() + public function setUp() : void { parent::setUp(); $this->dropCollection(); } - private function doTearDown() + public function tearDown() : void { if ($this->hasFailed()) { return; diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 4845683d7..19d6b5d49 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -17,7 +17,6 @@ use MongoDB\Operation\DatabaseCommand; use MongoDB\Operation\DropCollection; use stdClass; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use UnexpectedValueException; use function array_merge; use function count; @@ -42,15 +41,13 @@ abstract class FunctionalTestCase extends TestCase { - use SetUpTearDownTrait; - /** @var Manager */ protected $manager; /** @var array */ private $configuredFailPoints = []; - private function doSetUp() + public function setUp() : void { parent::setUp(); @@ -58,7 +55,7 @@ private function doSetUp() $this->configuredFailPoints = []; } - private function doTearDown() + public function tearDown() : void { $this->disableFailPoints(); diff --git a/tests/GridFS/FunctionalTestCase.php b/tests/GridFS/FunctionalTestCase.php index 428195284..58f2d83a9 100644 --- a/tests/GridFS/FunctionalTestCase.php +++ b/tests/GridFS/FunctionalTestCase.php @@ -5,7 +5,6 @@ use MongoDB\Collection; use MongoDB\GridFS\Bucket; use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function fopen; use function fwrite; use function get_resource_type; @@ -17,8 +16,6 @@ */ abstract class FunctionalTestCase extends BaseFunctionalTestCase { - use SetUpTearDownTrait; - /** @var Bucket */ protected $bucket; @@ -28,7 +25,7 @@ abstract class FunctionalTestCase extends BaseFunctionalTestCase /** @var Collection */ protected $filesCollection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/GridFS/ReadableStreamFunctionalTest.php b/tests/GridFS/ReadableStreamFunctionalTest.php index bdadcfa32..54789feca 100644 --- a/tests/GridFS/ReadableStreamFunctionalTest.php +++ b/tests/GridFS/ReadableStreamFunctionalTest.php @@ -8,7 +8,6 @@ use MongoDB\GridFS\Exception\CorruptFileException; use MongoDB\GridFS\ReadableStream; use MongoDB\Tests\CommandObserver; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function array_filter; /** @@ -16,12 +15,10 @@ */ class ReadableStreamFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var CollectionWrapper */ private $collectionWrapper; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/GridFS/StreamWrapperFunctionalTest.php b/tests/GridFS/StreamWrapperFunctionalTest.php index 88e1bd9b8..8b54b2fd6 100644 --- a/tests/GridFS/StreamWrapperFunctionalTest.php +++ b/tests/GridFS/StreamWrapperFunctionalTest.php @@ -4,7 +4,6 @@ use MongoDB\BSON\Binary; use MongoDB\BSON\UTCDateTime; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function fclose; use function feof; use function fread; @@ -20,9 +19,7 @@ */ class StreamWrapperFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/GridFS/WritableStreamFunctionalTest.php b/tests/GridFS/WritableStreamFunctionalTest.php index cadee3ad6..1ffd119b3 100644 --- a/tests/GridFS/WritableStreamFunctionalTest.php +++ b/tests/GridFS/WritableStreamFunctionalTest.php @@ -5,7 +5,6 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\CollectionWrapper; use MongoDB\GridFS\WritableStream; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function str_repeat; /** @@ -13,12 +12,10 @@ */ class WritableStreamFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var CollectionWrapper */ private $collectionWrapper; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Model/ChangeStreamIteratorTest.php b/tests/Model/ChangeStreamIteratorTest.php index 954ec4efc..5e13b3868 100644 --- a/tests/Model/ChangeStreamIteratorTest.php +++ b/tests/Model/ChangeStreamIteratorTest.php @@ -11,18 +11,15 @@ use MongoDB\Operation\Find; use MongoDB\Tests\CommandObserver; use MongoDB\Tests\FunctionalTestCase; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function array_merge; use function sprintf; class ChangeStreamIteratorTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index 4b28d9a75..d40a2573e 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -4,17 +4,14 @@ use MongoDB\Collection; use MongoDB\Tests\FunctionalTestCase; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function version_compare; class IndexInfoFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); @@ -22,7 +19,7 @@ private function doSetUp() $this->collection->drop(); } - private function doTearDown() + public function tearDown() : void { if ($this->hasFailed()) { return; diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php index d2de54d5e..5093ca2fd 100644 --- a/tests/Operation/BulkWriteFunctionalTest.php +++ b/tests/Operation/BulkWriteFunctionalTest.php @@ -11,17 +11,14 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\BulkWrite; use MongoDB\Tests\CommandObserver; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function version_compare; class BulkWriteFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php index a11846caf..7a2c5b5ff 100644 --- a/tests/Operation/DeleteFunctionalTest.php +++ b/tests/Operation/DeleteFunctionalTest.php @@ -9,17 +9,14 @@ use MongoDB\Exception\BadMethodCallException; use MongoDB\Operation\Delete; use MongoDB\Tests\CommandObserver; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function version_compare; class DeleteFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Operation/FunctionalTestCase.php b/tests/Operation/FunctionalTestCase.php index ef4e76b7c..6af42b3cb 100644 --- a/tests/Operation/FunctionalTestCase.php +++ b/tests/Operation/FunctionalTestCase.php @@ -5,23 +5,20 @@ use MongoDB\Driver\ReadConcern; use MongoDB\Driver\WriteConcern; use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; /** * Base class for Operation functional tests. */ abstract class FunctionalTestCase extends BaseFunctionalTestCase { - use SetUpTearDownTrait; - - private function doSetUp() + public function setUp() : void { parent::setUp(); $this->dropCollection(); } - private function doTearDown() + public function tearDown() : void { if ($this->hasFailed()) { return; diff --git a/tests/Operation/InsertManyFunctionalTest.php b/tests/Operation/InsertManyFunctionalTest.php index d8f105d64..262672930 100644 --- a/tests/Operation/InsertManyFunctionalTest.php +++ b/tests/Operation/InsertManyFunctionalTest.php @@ -10,17 +10,14 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\InsertMany; use MongoDB\Tests\CommandObserver; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function version_compare; class InsertManyFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Operation/InsertOneFunctionalTest.php b/tests/Operation/InsertOneFunctionalTest.php index b0eefded9..51603bb01 100644 --- a/tests/Operation/InsertOneFunctionalTest.php +++ b/tests/Operation/InsertOneFunctionalTest.php @@ -10,17 +10,14 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\InsertOne; use MongoDB\Tests\CommandObserver; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function version_compare; class InsertOneFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php index fc0c1552d..9b6ccbc9b 100644 --- a/tests/Operation/UpdateFunctionalTest.php +++ b/tests/Operation/UpdateFunctionalTest.php @@ -10,17 +10,14 @@ use MongoDB\Operation\Update; use MongoDB\Tests\CommandObserver; use MongoDB\UpdateResult; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function version_compare; class UpdateFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index a5ebae68d..45716f90e 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -21,7 +21,6 @@ use PHPUnit\Framework\ExpectationFailedException; use ReflectionClass; use stdClass; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function array_diff_key; use function array_map; use function bin2hex; @@ -37,8 +36,6 @@ */ class WatchFunctionalTest extends FunctionalTestCase { - use SetUpTearDownTrait; - const INTERRUPTED = 11601; const NOT_PRIMARY = 10107; @@ -48,7 +45,7 @@ class WatchFunctionalTest extends FunctionalTestCase /** @var array */ private $defaultOptions = ['maxAwaitTimeMS' => 500]; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/SpecTests/AtlasDataLakeSpecTest.php b/tests/SpecTests/AtlasDataLakeSpecTest.php index 96e992f18..d66f6be4a 100644 --- a/tests/SpecTests/AtlasDataLakeSpecTest.php +++ b/tests/SpecTests/AtlasDataLakeSpecTest.php @@ -6,7 +6,6 @@ use MongoDB\Driver\Cursor; use MongoDB\Tests\CommandObserver; use stdClass; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function basename; use function current; use function explode; @@ -21,9 +20,7 @@ */ class AtlasDataLakeSpecTest extends FunctionalTestCase { - use SetUpTearDownTrait; - - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 2853ec26c..f7d9aaf1f 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -18,7 +18,6 @@ use MongoDB\Tests\CommandObserver; use PHPUnit\Framework\SkippedTestError; use stdClass; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use Throwable; use UnexpectedValueException; use function base64_decode; @@ -40,11 +39,9 @@ */ class ClientSideEncryptionSpecTest extends FunctionalTestCase { - use SetUpTearDownTrait; - const LOCAL_MASTERKEY = 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk'; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index b6d48a213..04bf6ac66 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -10,7 +10,6 @@ use MultipleIterator; use PHPUnit\Framework\SkippedTest; use stdClass; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use UnexpectedValueException; use function in_array; use function json_encode; @@ -26,8 +25,6 @@ */ class FunctionalTestCase extends BaseFunctionalTestCase { - use SetUpTearDownTrait; - const TOPOLOGY_SINGLE = 'single'; const TOPOLOGY_REPLICASET = 'replicaset'; const TOPOLOGY_SHARDED = 'sharded'; @@ -35,14 +32,14 @@ class FunctionalTestCase extends BaseFunctionalTestCase /** @var Context|null */ private $context; - private function doSetUp() + public function setUp() : void { parent::setUp(); $this->context = null; } - private function doTearDown() + public function tearDown() : void { $this->context = null; diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php index 135e3deb5..60680dc04 100644 --- a/tests/SpecTests/PrimaryStepDownSpecTest.php +++ b/tests/SpecTests/PrimaryStepDownSpecTest.php @@ -12,7 +12,6 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Operation\BulkWrite; use MongoDB\Tests\CommandObserver; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use UnexpectedValueException; use function current; use function sprintf; @@ -22,8 +21,6 @@ */ class PrimaryStepDownSpecTest extends FunctionalTestCase { - use SetUpTearDownTrait; - const INTERRUPTED_AT_SHUTDOWN = 11600; const NOT_PRIMARY = 10107; const SHUTDOWN_IN_PROGRESS = 91; @@ -34,7 +31,7 @@ class PrimaryStepDownSpecTest extends FunctionalTestCase /** @var Collection */ private $collection; - private function doSetUp() + public function setUp() : void { parent::setUp(); diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 0241d2e95..f6359d529 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -9,7 +9,6 @@ use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use stdClass; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function array_unique; use function basename; use function count; @@ -25,8 +24,6 @@ */ class TransactionsSpecTest extends FunctionalTestCase { - use SetUpTearDownTrait; - const INTERRUPTED = 11601; /** @@ -43,7 +40,7 @@ class TransactionsSpecTest extends FunctionalTestCase 'transactions/errors-client: Client side error when transaction is in progress' => 'PHPLIB-665', ]; - private function doSetUp() + public function setUp() : void { parent::setUp(); @@ -52,7 +49,7 @@ private function doSetUp() $this->skipIfTransactionsAreNotSupported(); } - private function doTearDown() + public function tearDown() : void { if ($this->hasFailed()) { static::killAllSessions(); diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 42725523c..47f00cf32 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -7,7 +7,6 @@ use MongoDB\Tests\FunctionalTestCase; use PHPUnit\Framework\SkippedTest; use PHPUnit\Framework\Warning; -use Symfony\Bridge\PhpUnit\SetUpTearDownTrait; use function basename; use function dirname; use function glob; @@ -19,8 +18,6 @@ */ class UnifiedSpecTest extends FunctionalTestCase { - use SetUpTearDownTrait; - /** @var array */ private static $incompleteTests = [ // PHPLIB-573 and DRIVERS-1340 @@ -111,7 +108,7 @@ class UnifiedSpecTest extends FunctionalTestCase /** @var UnifiedTestRunner */ private static $runner; - private static function doSetUpBeforeClass() + public static function setUpBeforeClass() : void { parent::setUpBeforeClass(); @@ -120,7 +117,7 @@ private static function doSetUpBeforeClass() self::$runner = new UnifiedTestRunner(static::getUri(true)); } - private function doSetUp() + public function setUp() : void { parent::setUp(); From bf6da6c90c2b94487184c32d8d831e68793e3f85 Mon Sep 17 00:00:00 2001 From: Tanli Su <46271307+tanlisu@users.noreply.github.com> Date: Fri, 2 Jul 2021 14:46:15 -0400 Subject: [PATCH 047/321] PHPLIB-636: ListIndexes should use CommandException for catching missing namespace and database errors (#837) --- src/Operation/ListIndexes.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index 9848a8847..9702e34d3 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -19,6 +19,7 @@ use EmptyIterator; use MongoDB\Driver\Command; +use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\Server; use MongoDB\Driver\Session; @@ -135,7 +136,7 @@ private function executeCommand(Server $server) try { $cursor = $server->executeReadCommand($this->databaseName, new Command($cmd), $this->createOptions()); - } catch (DriverRuntimeException $e) { + } catch (CommandException $e) { /* The server may return an error if the collection does not exist. * Check for possible error codes (see: SERVER-20463) and return an * empty iterator instead of throwing. From a518473c7e0334619dd13ab37df0cefabb35be66 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 24 Jun 2021 15:12:05 -0400 Subject: [PATCH 048/321] PHPLIB-655: Sync Versioned API tests Synced with mongodb/specifications@72249aad5068f9a4d24930e723e90d92bb82b6cb --- .../crud-api-version-1-strict.json | 20 +- .../versioned-api/crud-api-version-1.json | 19 +- ...ommand-helper-no-api-version-declared.json | 12 +- .../test-commands-deprecation-errors.json | 2 +- .../test-commands-strict-mode.json | 5 +- .../versioned-api/transaction-handling.json | 207 ++---------------- 6 files changed, 53 insertions(+), 212 deletions(-) diff --git a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json index e3bb4130b..29a0ec4e3 100644 --- a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json +++ b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json @@ -1,6 +1,6 @@ { "description": "CRUD Api Version 1 (strict)", - "schemaVersion": "1.1", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "4.9" @@ -141,6 +141,11 @@ }, { "description": "aggregate on database appends declared API version", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "operations": [ { "name": "aggregate", @@ -608,7 +613,6 @@ }, { "description": "estimatedDocumentCount appends declared API version", - "skipReason": "DRIVERS-1561 collStats is not in API version 1", "operations": [ { "name": "estimatedDocumentCount", @@ -652,7 +656,7 @@ ] }, { - "description": "find command with declared API version appends to the command, but getMore does not", + "description": "find and getMore append API version", "operations": [ { "name": "find", @@ -713,14 +717,10 @@ "long" ] }, - "apiVersion": { - "$$exists": false - }, - "apiStrict": { - "$$exists": false - }, + "apiVersion": "1", + "apiStrict": true, "apiDeprecationErrors": { - "$$exists": false + "$$unsetOrMatches": false } } } diff --git a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json index 917185837..1f135eea1 100644 --- a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json +++ b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json @@ -1,6 +1,6 @@ { "description": "CRUD Api Version 1", - "schemaVersion": "1.1", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "4.9" @@ -141,6 +141,11 @@ }, { "description": "aggregate on database appends declared API version", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "operations": [ { "name": "aggregate", @@ -643,7 +648,7 @@ ] }, { - "description": "find command with declared API version appends to the command, but getMore does not", + "description": "find and getMore append API version", "operations": [ { "name": "find", @@ -704,15 +709,11 @@ "long" ] }, - "apiVersion": { - "$$exists": false - }, + "apiVersion": "1", "apiStrict": { - "$$exists": false + "$$unsetOrMatches": false }, - "apiDeprecationErrors": { - "$$exists": false - } + "apiDeprecationErrors": true } } } diff --git a/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json b/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json index e901887e4..17e0126d1 100644 --- a/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json +++ b/tests/UnifiedSpecTests/versioned-api/runcommand-helper-no-api-version-declared.json @@ -1,6 +1,6 @@ { "description": "RunCommand helper: No API version declared", - "schemaVersion": "1.1", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "4.9", @@ -29,6 +29,11 @@ "tests": [ { "description": "runCommand does not inspect or change the command document", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "operations": [ { "name": "runCommand", @@ -72,6 +77,11 @@ }, { "description": "runCommand does not prevent sending invalid API version declarations", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "operations": [ { "name": "runCommand", diff --git a/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json b/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json index 6dc59a045..0668df830 100644 --- a/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json +++ b/tests/UnifiedSpecTests/versioned-api/test-commands-deprecation-errors.json @@ -6,7 +6,7 @@ "minServerVersion": "4.9", "serverParameters": { "enableTestCommands": true, - "acceptAPIVersion2": true, + "acceptApiVersion2": true, "requireApiVersion": false } } diff --git a/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json b/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json index 1705ba7bf..9c4ebea78 100644 --- a/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json +++ b/tests/UnifiedSpecTests/versioned-api/test-commands-strict-mode.json @@ -1,12 +1,13 @@ { "description": "Test commands: strict mode", - "schemaVersion": "1.1", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "4.9", "serverParameters": { "enableTestCommands": true - } + }, + "serverless": "forbid" } ], "createEntities": [ diff --git a/tests/UnifiedSpecTests/versioned-api/transaction-handling.json b/tests/UnifiedSpecTests/versioned-api/transaction-handling.json index a740405d3..c00c5240a 100644 --- a/tests/UnifiedSpecTests/versioned-api/transaction-handling.json +++ b/tests/UnifiedSpecTests/versioned-api/transaction-handling.json @@ -1,12 +1,13 @@ { "description": "Transaction handling", - "schemaVersion": "1.1", + "schemaVersion": "1.3", "runOnRequirements": [ { "minServerVersion": "4.9", "topologies": [ "replicaset", - "sharded-replicaset" + "sharded-replicaset", + "load-balanced" ] } ], @@ -53,17 +54,6 @@ "apiDeprecationErrors": { "$$unsetOrMatches": false } - }, - { - "apiVersion": { - "$$exists": false - }, - "apiStrict": { - "$$exists": false - }, - "apiDeprecationErrors": { - "$$exists": false - } } ] }, @@ -97,12 +87,13 @@ ], "tests": [ { - "description": "Only the first command in a transaction declares an API version", + "description": "All commands in a transaction declare an API version", "runOnRequirements": [ { "topologies": [ "replicaset", - "sharded-replicaset" + "sharded-replicaset", + "load-balanced" ] } ], @@ -193,119 +184,6 @@ "lsid": { "$$sessionLsid": "session" }, - "apiVersion": { - "$$exists": false - }, - "apiStrict": { - "$$exists": false - }, - "apiDeprecationErrors": { - "$$exists": false - } - } - } - }, - { - "commandStartedEvent": { - "command": { - "commitTransaction": 1, - "lsid": { - "$$sessionLsid": "session" - }, - "apiVersion": { - "$$exists": false - }, - "apiStrict": { - "$$exists": false - }, - "apiDeprecationErrors": { - "$$exists": false - } - } - } - } - ] - } - ] - }, - { - "description": "Committing a transaction twice does not append server API options", - "runOnRequirements": [ - { - "topologies": [ - "replicaset", - "sharded-replicaset" - ] - } - ], - "operations": [ - { - "name": "startTransaction", - "object": "session" - }, - { - "name": "insertOne", - "object": "collection", - "arguments": { - "session": "session", - "document": { - "_id": 6, - "x": 66 - } - }, - "expectResult": { - "$$unsetOrMatches": { - "insertedId": { - "$$unsetOrMatches": 6 - } - } - } - }, - { - "name": "insertOne", - "object": "collection", - "arguments": { - "session": "session", - "document": { - "_id": 7, - "x": 77 - } - }, - "expectResult": { - "$$unsetOrMatches": { - "insertedId": { - "$$unsetOrMatches": 7 - } - } - } - }, - { - "name": "commitTransaction", - "object": "session" - }, - { - "name": "commitTransaction", - "object": "session" - } - ], - "expectEvents": [ - { - "client": "client", - "events": [ - { - "commandStartedEvent": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 6, - "x": 66 - } - ], - "lsid": { - "$$sessionLsid": "session" - }, - "startTransaction": true, "apiVersion": "1", "apiStrict": { "$$unsetOrMatches": false @@ -316,31 +194,6 @@ } } }, - { - "commandStartedEvent": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 7, - "x": 77 - } - ], - "lsid": { - "$$sessionLsid": "session" - }, - "apiVersion": { - "$$exists": false - }, - "apiStrict": { - "$$exists": false - }, - "apiDeprecationErrors": { - "$$exists": false - } - } - } - }, { "commandStartedEvent": { "command": { @@ -348,33 +201,12 @@ "lsid": { "$$sessionLsid": "session" }, - "apiVersion": { - "$$exists": false - }, - "apiStrict": { - "$$exists": false - }, - "apiDeprecationErrors": { - "$$exists": false - } - } - } - }, - { - "commandStartedEvent": { - "command": { - "commitTransaction": 1, - "lsid": { - "$$sessionLsid": "session" - }, - "apiVersion": { - "$$exists": false - }, + "apiVersion": "1", "apiStrict": { - "$$exists": false + "$$unsetOrMatches": false }, "apiDeprecationErrors": { - "$$exists": false + "$$unsetOrMatches": false } } } @@ -384,12 +216,13 @@ ] }, { - "description": "abortTransaction does not include an API version", + "description": "abortTransaction includes an API version", "runOnRequirements": [ { "topologies": [ "replicaset", - "sharded-replicaset" + "sharded-replicaset", + "load-balanced" ] } ], @@ -480,14 +313,12 @@ "lsid": { "$$sessionLsid": "session" }, - "apiVersion": { - "$$exists": false - }, + "apiVersion": "1", "apiStrict": { - "$$exists": false + "$$unsetOrMatches": false }, "apiDeprecationErrors": { - "$$exists": false + "$$unsetOrMatches": false } } } @@ -499,14 +330,12 @@ "lsid": { "$$sessionLsid": "session" }, - "apiVersion": { - "$$exists": false - }, + "apiVersion": "1", "apiStrict": { - "$$exists": false + "$$unsetOrMatches": false }, "apiDeprecationErrors": { - "$$exists": false + "$$unsetOrMatches": false } } } From 50348c25b1b3bb368c3db34bf0f4f6d5b8ff44cf Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 24 Jun 2021 15:18:50 -0400 Subject: [PATCH 049/321] PHPLIB-666: Sync command monitoring tests for 5.0 cursor behavior Synced with mongodb/specifications@9da20b4b28f99037215ddfd78f5b0df04897a0be --- tests/SpecTests/command-monitoring/find.json | 3 ++- tests/UnifiedSpecTests/valid-pass/poc-command-monitoring.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/SpecTests/command-monitoring/find.json b/tests/SpecTests/command-monitoring/find.json index 039c5fead..55b185cc5 100644 --- a/tests/SpecTests/command-monitoring/find.json +++ b/tests/SpecTests/command-monitoring/find.json @@ -413,8 +413,9 @@ ] }, { - "description": "A successful find event with a getmore and the server kills the cursor", + "description": "A successful find event with a getmore and the server kills the cursor (<= 4.4)", "ignore_if_server_version_less_than": "3.1", + "ignore_if_server_version_greater_than": "4.4", "ignore_if_topology_type": [ "sharded" ], diff --git a/tests/UnifiedSpecTests/valid-pass/poc-command-monitoring.json b/tests/UnifiedSpecTests/valid-pass/poc-command-monitoring.json index 499396e0b..fe0a5ae99 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-command-monitoring.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-command-monitoring.json @@ -57,10 +57,11 @@ ], "tests": [ { - "description": "A successful find event with a getmore and the server kills the cursor", + "description": "A successful find event with a getmore and the server kills the cursor (<= 4.4)", "runOnRequirements": [ { "minServerVersion": "3.1", + "maxServerVersion": "4.4.99", "topologies": [ "single", "replicaset" From bb41ba3d26d892a5a86c353c67f8d99690eb8b93 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 28 Jun 2021 11:21:37 -0400 Subject: [PATCH 050/321] PHPLIB-665: Sync spec tests for dots/dollars This updates individual tests pertaining to dots/dollars. Synced with mongodb/specifications@44f83106033a609f2af40e3e4d99852a03096ba5 Removes skips previously added in a66f31f3fab2c9b08402770489e0f88d44dce9f3 and ea9853af30c3eb899745c4a67dfec21932a37c53 --- tests/SpecTests/TransactionsSpecTest.php | 2 - .../SpecTests/transactions/errors-client.json | 26 ++++---- tests/UnifiedSpecTests/UnifiedSpecTest.php | 61 ------------------- .../crud/insertMany-dots_and_dollars.json | 36 ++++++----- .../crud/insertOne-dots_and_dollars.json | 50 ++++++++------- .../UnifiedSpecTests/valid-pass/poc-crud.json | 19 +++--- .../valid-pass/poc-retryable-writes.json | 3 - .../valid-pass/poc-transactions.json | 11 ++-- 8 files changed, 80 insertions(+), 128 deletions(-) diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index f6359d529..0b2b67595 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -36,8 +36,6 @@ class TransactionsSpecTest extends FunctionalTestCase 'transactions/mongos-recovery-token: commitTransaction retry fails on new mongos' => 'isMaster failpoints cannot be disabled', 'transactions/pin-mongos: remain pinned after non-transient error on commit' => 'Blocked on SPEC-1320', 'transactions/pin-mongos: unpin after transient error within a transaction and commit' => 'isMaster failpoints cannot be disabled', - 'transactions/errors-client: Client side error in command starting transaction' => 'PHPLIB-665', - 'transactions/errors-client: Client side error when transaction is in progress' => 'PHPLIB-665', ]; public function setUp() : void diff --git a/tests/SpecTests/transactions/errors-client.json b/tests/SpecTests/transactions/errors-client.json index 4bd1c0eb3..15fae96fe 100644 --- a/tests/SpecTests/transactions/errors-client.json +++ b/tests/SpecTests/transactions/errors-client.json @@ -25,14 +25,15 @@ "object": "session0" }, { - "name": "insertOne", + "name": "updateOne", "object": "collection", "arguments": { "session": "session0", - "document": { - "_id": { - ".": "." - } + "filter": { + "_id": 1 + }, + "update": { + "x": 1 } }, "error": true @@ -60,22 +61,23 @@ "arguments": { "session": "session0", "document": { - "_id": 4 + "_id": 1 } }, "result": { - "insertedId": 4 + "insertedId": 1 } }, { - "name": "insertOne", + "name": "updateOne", "object": "collection", "arguments": { "session": "session0", - "document": { - "_id": { - ".": "." - } + "filter": { + "_id": 1 + }, + "update": { + "x": 1 } }, "error": true diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 47f00cf32..c53ae256a 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -42,67 +42,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - // CDRIVER-3895 and PHPC-1765 - 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with top-level dotted key' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with dollar-prefixed key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-insertOne-dots_and_dollars: Inserting document with dotted key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with top-level dotted key on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with top-level dotted key on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateMany-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/bulkWrite-updateOne-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndReplace-dots_and_dollars: Replacing document with top-level dotted key on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndReplace-dots_and_dollars: Replacing document with top-level dotted key on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dotted key in embedded doc on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndReplace-dots_and_dollars: Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/findOneAndUpdate-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertMany-dots_and_dollars: Inserting document with top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertMany-dots_and_dollars: Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertMany-dots_and_dollars: Inserting document with top-level dotted key' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertMany-dots_and_dollars: Inserting document with dollar-prefixed key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertMany-dots_and_dollars: Inserting document with dotted key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with top-level dollar-prefixed key on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with top-level dotted key' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with dollar-prefixed key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with dotted key in embedded doc' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with dollar-prefixed key in _id yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with dotted key in _id on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with dotted key in _id on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Inserting document with DBRef-like keys' => 'CDRIVER-3895 and PHPC-1765', - 'crud/insertOne-dots_and_dollars: Unacknowledged write using dollar-prefixed or dotted keys may be silently rejected on pre-5.0 server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Replacing document with top-level dotted key on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Replacing document with top-level dotted key on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Replacing document with dollar-prefixed key in embedded doc on pre-5.0 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on 3.6+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Replacing document with dotted key in embedded doc on pre-3.6 server yields server-side error' => 'CDRIVER-3895 and PHPC-1765', - 'crud/replaceOne-dots_and_dollars: Unacknowledged write using dollar-prefixed or dotted keys may be silently rejected on pre-5.0 server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateMany-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateMany-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateMany-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateMany-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateOne-dots_and_dollars: Updating document to set top-level dollar-prefixed key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateOne-dots_and_dollars: Updating document to set top-level dotted key on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateOne-dots_and_dollars: Updating document to set dollar-prefixed key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'crud/updateOne-dots_and_dollars: Updating document to set dotted key in embedded doc on 5.0+ server' => 'CDRIVER-3895 and PHPC-1765', - 'valid-pass/poc-transactions: Client side error in command starting transaction' => 'PHPLIB-665', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json index 3b66ac062..eed8997df 100644 --- a/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json +++ b/tests/UnifiedSpecTests/crud/insertMany-dots_and_dollars.json @@ -53,10 +53,11 @@ ] }, "expectResult": { - "insertedCount": 1, - "insertedIds": { - "$$unsetOrMatches": { - "0": 1 + "$$unsetOrMatches": { + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } } } } @@ -162,10 +163,11 @@ ] }, "expectResult": { - "insertedCount": 1, - "insertedIds": { - "$$unsetOrMatches": { - "0": 1 + "$$unsetOrMatches": { + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } } } } @@ -221,10 +223,11 @@ ] }, "expectResult": { - "insertedCount": 1, - "insertedIds": { - "$$unsetOrMatches": { - "0": 1 + "$$unsetOrMatches": { + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } } } } @@ -284,10 +287,11 @@ ] }, "expectResult": { - "insertedCount": 1, - "insertedIds": { - "$$unsetOrMatches": { - "0": 1 + "$$unsetOrMatches": { + "insertedIds": { + "$$unsetOrMatches": { + "0": 1 + } } } } diff --git a/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json b/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json index 1a30df4a0..fdc17af2e 100644 --- a/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json +++ b/tests/UnifiedSpecTests/crud/insertOne-dots_and_dollars.json @@ -63,9 +63,10 @@ } }, "expectResult": { - "insertedCount": 1, - "insertedId": { - "$$unsetOrMatches": 1 + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } } } } @@ -166,9 +167,10 @@ } }, "expectResult": { - "insertedCount": 1, - "insertedId": { - "$$unsetOrMatches": 1 + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } } } } @@ -221,9 +223,10 @@ } }, "expectResult": { - "insertedCount": 1, - "insertedId": { - "$$unsetOrMatches": 1 + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } } } } @@ -280,9 +283,10 @@ } }, "expectResult": { - "insertedCount": 1, - "insertedId": { - "$$unsetOrMatches": 1 + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } } } } @@ -390,10 +394,11 @@ } }, "expectResult": { - "insertedCount": 1, - "insertedId": { - "$$unsetOrMatches": { - "a.b": 1 + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": { + "a.b": 1 + } } } } @@ -501,9 +506,10 @@ } }, "expectResult": { - "insertedCount": 1, - "insertedId": { - "$$unsetOrMatches": 1 + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 1 + } } } } @@ -564,8 +570,10 @@ } }, "expectResult": { - "acknowledged": { - "$$unsetOrMatches": false + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } } } } diff --git a/tests/UnifiedSpecTests/valid-pass/poc-crud.json b/tests/UnifiedSpecTests/valid-pass/poc-crud.json index 2ed86d615..7bb072de8 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-crud.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-crud.json @@ -1,6 +1,6 @@ { "description": "poc-crud", - "schemaVersion": "1.0", + "schemaVersion": "1.4", "createEntities": [ { "client": { @@ -242,12 +242,14 @@ }, "expectError": { "expectResult": { - "deletedCount": 0, - "insertedCount": 2, - "matchedCount": 0, - "modifiedCount": 0, - "upsertedCount": 0, - "upsertedIds": {} + "$$unsetOrMatches": { + "deletedCount": 0, + "insertedCount": 2, + "matchedCount": 0, + "modifiedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } } } } @@ -406,7 +408,8 @@ "description": "Aggregate with $listLocalSessions", "runOnRequirements": [ { - "minServerVersion": "3.6.0" + "minServerVersion": "3.6.0", + "serverless": "forbid" } ], "operations": [ diff --git a/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json b/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json index 30c1d5415..50160799f 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json @@ -298,9 +298,6 @@ }, "expectResult": { "$$unsetOrMatches": { - "insertedCount": { - "$$unsetOrMatches": 2 - }, "insertedIds": { "$$unsetOrMatches": { "0": 3, diff --git a/tests/UnifiedSpecTests/valid-pass/poc-transactions.json b/tests/UnifiedSpecTests/valid-pass/poc-transactions.json index 62528f9ce..0355ca206 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-transactions.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-transactions.json @@ -61,14 +61,15 @@ "object": "session0" }, { - "name": "insertOne", + "name": "updateOne", "object": "collection0", "arguments": { "session": "session0", - "document": { - "_id": { - ".": "." - } + "filter": { + "_id": 1 + }, + "update": { + "x": 1 } }, "expectError": { From aed48fbc0dfaea5a16f2b3e9896212a40dbf3267 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 26 May 2021 12:50:30 +0200 Subject: [PATCH 051/321] PHPLIB-660 Add 5.0 to the test matrix --- .evergreen/config.yml | 6 +++++- .github/workflows/tests.yml | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 0cbdb4d34..7cfd008f0 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -420,6 +420,10 @@ axes: display_name: "latest" variables: VERSION: "latest" + - id: "5.0" + display_name: "5.0" + variables: + VERSION: "5.0" - id: "4.4" display_name: "4.4" variables: @@ -626,7 +630,7 @@ buildvariants: - name: "test-atlas-data-lake" - matrix_name: "test-versioned-api" - matrix_spec: { "php-edge-versions": "latest-stable", "versions": "latest", "driver-versions": "latest" } + matrix_spec: { "php-edge-versions": "latest-stable", "versions": ["5.0", "latest"], "driver-versions": "latest" } display_name: "Versioned API - ${versions}" run_on: rhel70 tasks: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5e1a46d2a..dbde407ee 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,6 +30,11 @@ jobs: topology: - "server" include: + - os: "ubuntu-20.04" + php-version: "8.0" + mongodb-version: "5.0" + driver-version: "mongodb/mongo-php-driver@master" + topology: "server" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" From 2422da7352356a566dc92d830555a5089151ab1e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 14:45:20 -0400 Subject: [PATCH 052/321] Explicit result iteration and require filter/pipeline args Remove automatic result iteration in Operation::execute(), since ChangeStreams will no longer be the lone exception once createFindCursor is implemented. Additionally, filter/pipeline args need not default since they are required by the CRUD and change stream specs and present in all valid spec tests. The previous behavior would conflict with a forthcoming "createFindCursor fails if filter is not specified" test. --- tests/UnifiedSpecTests/Operation.php | 39 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 0f93d094b..7b015eadb 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -18,7 +18,6 @@ use PHPUnit\Framework\AssertionFailedError; use stdClass; use Throwable; -use Traversable; use function array_diff_key; use function array_key_exists; use function array_map; @@ -204,10 +203,6 @@ private function execute() Assert::fail('Unsupported entity type: ' . get_class($object)); } - if ($result instanceof Traversable && ! $result instanceof ChangeStream) { - return iterator_to_array($result); - } - return $result; } @@ -249,16 +244,16 @@ private function executeForClient(Client $client) switch ($this->name) { case 'createChangeStream': $changeStream = $client->watch( - $args['pipeline'] ?? [], + $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); $changeStream->rewind(); return $changeStream; case 'listDatabaseNames': - return $client->listDatabaseNames($args); + return iterator_to_array($client->listDatabaseNames($args)); case 'listDatabases': - return $client->listDatabases($args); + return iterator_to_array($client->listDatabases($args)); default: Assert::fail('Unsupported client operation: ' . $this->name); } @@ -270,10 +265,10 @@ private function executeForCollection(Collection $collection) switch ($this->name) { case 'aggregate': - return $collection->aggregate( + return iterator_to_array($collection->aggregate( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) - ); + )); case 'bulkWrite': return $collection->bulkWrite( array_map('self::prepareBulkWriteRequest', $args['requests']), @@ -281,7 +276,7 @@ private function executeForCollection(Collection $collection) ); case 'createChangeStream': $changeStream = $collection->watch( - $args['pipeline'] ?? [], + $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); $changeStream->rewind(); @@ -299,9 +294,8 @@ private function executeForCollection(Collection $collection) ); case 'count': case 'countDocuments': - case 'find': return $collection->{$this->name}( - $args['filter'] ?? [], + $args['filter'], array_diff_key($args, ['filter' => 1]) ); case 'estimatedDocumentCount': @@ -321,11 +315,16 @@ private function executeForCollection(Collection $collection) return $collection->distinct( $args['fieldName'], - $args['filter'] ?? [], + $args['filter'], array_diff_key($args, ['fieldName' => 1, 'filter' => 1]) ); case 'drop': return $collection->drop($args); + case 'find': + return iterator_to_array($collection->find( + $args['filter'], + array_diff_key($args, ['filter' => 1]) + )); case 'findOne': return $collection->findOne($args['filter'], array_diff_key($args, ['filter' => 1])); case 'findOneAndReplace': @@ -378,7 +377,7 @@ private function executeForCollection(Collection $collection) array_diff_key($args, ['document' => 1]) ); case 'listIndexes': - return $collection->listIndexes($args); + return iterator_to_array($collection->listIndexes($args)); case 'mapReduce': return $collection->mapReduce( $args['map'], @@ -397,13 +396,13 @@ private function executeForDatabase(Database $database) switch ($this->name) { case 'aggregate': - return $database->aggregate( + return iterator_to_array($database->aggregate( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) - ); + )); case 'createChangeStream': $changeStream = $database->watch( - $args['pipeline'] ?? [], + $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); $changeStream->rewind(); @@ -420,9 +419,9 @@ private function executeForDatabase(Database $database) array_diff_key($args, ['collection' => 1]) ); case 'listCollectionNames': - return $database->listCollectionNames($args); + return iterator_to_array($database->listCollectionNames($args)); case 'listCollections': - return $database->listCollections($args); + return iterator_to_array($database->listCollections($args)); case 'runCommand': return $database->command( $args['command'], From 237397cae2823211e81db4d1335ae2391594967d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 15:02:25 -0400 Subject: [PATCH 053/321] Remove extra call to rewind() in createChangeStream A newly created ChangeStream will have a null key, so we can rely on iterateUntilDocumentOrError to initially rewind the ChangeStream. --- tests/UnifiedSpecTests/Operation.php | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 7b015eadb..7f403d680 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -243,13 +243,10 @@ private function executeForClient(Client $client) switch ($this->name) { case 'createChangeStream': - $changeStream = $client->watch( + return $client->watch( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); - $changeStream->rewind(); - - return $changeStream; case 'listDatabaseNames': return iterator_to_array($client->listDatabaseNames($args)); case 'listDatabases': @@ -275,13 +272,10 @@ private function executeForCollection(Collection $collection) array_diff_key($args, ['requests' => 1]) ); case 'createChangeStream': - $changeStream = $collection->watch( + return $collection->watch( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); - $changeStream->rewind(); - - return $changeStream; case 'createIndex': return $collection->createIndex( $args['keys'], @@ -401,13 +395,10 @@ private function executeForDatabase(Database $database) array_diff_key($args, ['pipeline' => 1]) )); case 'createChangeStream': - $changeStream = $database->watch( + return $database->watch( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); - $changeStream->rewind(); - - return $changeStream; case 'createCollection': return $database->createCollection( $args['collection'], From 2fc7e896847bfd952899f10d98e62fd83037954d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 14:53:47 -0400 Subject: [PATCH 054/321] PHPLIB-669: Unified test runner changes for load balancer support Sync valid-pass and valid-fail tests with mongodb/specifications@ed4e62b48939378b814cbd7d9d4939a2c1076a6b Moves caching of server environment to checkRunOnRequirements Detection of load balancers will be addressed after driver support is implemented (PHPLIB-671) --- tests/UnifiedSpecTests/Context.php | 7 +- tests/UnifiedSpecTests/EntityMap.php | 14 ++ tests/UnifiedSpecTests/EventObserver.php | 3 + tests/UnifiedSpecTests/Operation.php | 77 +++++++- tests/UnifiedSpecTests/RunOnRequirement.php | 29 ++- tests/UnifiedSpecTests/UnifiedSpecTest.php | 5 + tests/UnifiedSpecTests/UnifiedTestRunner.php | 136 ++++++------- .../assertNumberConnectionsCheckedOut.json | 63 ++++++ .../valid-fail/entity-find-cursor.json | 62 ++++++ .../valid-fail/ignoreResultAndError.json | 72 +++++++ .../assertNumberConnectionsCheckedOut.json | 27 +++ .../valid-pass/entity-client-cmap-events.json | 71 +++++++ .../valid-pass/entity-find-cursor.json | 182 ++++++++++++++++++ .../expectedEventsForClient-eventType.json | 126 ++++++++++++ .../valid-pass/ignoreResultAndError.json | 59 ++++++ 15 files changed, 856 insertions(+), 77 deletions(-) create mode 100644 tests/UnifiedSpecTests/valid-fail/assertNumberConnectionsCheckedOut.json create mode 100644 tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json create mode 100644 tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json create mode 100644 tests/UnifiedSpecTests/valid-pass/assertNumberConnectionsCheckedOut.json create mode 100644 tests/UnifiedSpecTests/valid-pass/entity-client-cmap-events.json create mode 100644 tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json create mode 100644 tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-eventType.json create mode 100644 tests/UnifiedSpecTests/valid-pass/ignoreResultAndError.json diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index cf2c27f20..82712e559 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -29,6 +29,7 @@ use function PHPUnit\Framework\assertNotEmpty; use function PHPUnit\Framework\assertNotFalse; use function PHPUnit\Framework\assertNotSame; +use function PHPUnit\Framework\assertSame; use function PHPUnit\Framework\assertStringContainsString; use function PHPUnit\Framework\assertStringStartsWith; use function strlen; @@ -171,13 +172,17 @@ public function assertExpectedEventsForClients(array $expectedEventsForClients) foreach ($expectedEventsForClients as $expectedEventsForClient) { assertIsObject($expectedEventsForClient); - Util::assertHasOnlyKeys($expectedEventsForClient, ['client', 'events']); + Util::assertHasOnlyKeys($expectedEventsForClient, ['client', 'events', 'eventType']); $client = $expectedEventsForClient->client ?? null; + $eventType = $expectedEventsForClient->eventType ?? 'command'; $expectedEvents = $expectedEventsForClient->events ?? null; assertIsString($client); assertArrayHasKey($client, $this->eventObserversByClient); + /* Note: PHPC does not implement CMAP. Any tests expecting CMAP + * events should be skipped explicitly. */ + assertSame('command', $eventType); assertIsArray($expectedEvents); $this->eventObserversByClient[$client]->assert($expectedEvents); diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php index 5b983b6b1..8184cbc7f 100644 --- a/tests/UnifiedSpecTests/EntityMap.php +++ b/tests/UnifiedSpecTests/EntityMap.php @@ -7,6 +7,7 @@ use MongoDB\Client; use MongoDB\Collection; use MongoDB\Database; +use MongoDB\Driver\Cursor; use MongoDB\Driver\Session; use MongoDB\GridFS\Bucket; use MongoDB\Tests\UnifiedSpecTests\Constraint\IsBsonType; @@ -16,6 +17,7 @@ use function array_key_exists; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertArrayNotHasKey; +use function PHPUnit\Framework\assertInstanceOf; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertThat; use function PHPUnit\Framework\isInstanceOf; @@ -128,6 +130,17 @@ public function getRoot() : self }; } + /** + * Closes a cursor by removing it from the entity map. + * + * @see Operation::executeForCursor() + */ + public function closeCursor(string $cursorId) + { + assertInstanceOf(Cursor::class, $this[$cursorId]); + unset($this->map[$cursorId]); + } + public function getClient(string $clientId) : Client { return $this[$clientId]; @@ -170,6 +183,7 @@ private static function isSupportedType() : Constraint isInstanceOf(Session::class), isInstanceOf(Bucket::class), isInstanceOf(ChangeStream::class), + isInstanceOf(Cursor::class), IsBsonType::any() ); } diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index 19c86c19a..bd7e54d3f 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -199,6 +199,7 @@ private function assertEvent($actual, stdClass $expected, string $message) private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass $expected, string $message) { + // TODO: Assert hasServiceId (blocked on PHPC-1752) Util::assertHasOnlyKeys($expected, ['command', 'commandName', 'databaseName']); if (isset($expected->command)) { @@ -220,6 +221,7 @@ private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdClass $expected, string $message) { + // TODO: Assert hasServiceId (blocked on PHPC-1752) Util::assertHasOnlyKeys($expected, ['reply', 'commandName']); if (isset($expected->reply)) { @@ -236,6 +238,7 @@ private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdC private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $expected, string $message) { + // TODO: Assert hasServiceId (blocked on PHPC-1752) Util::assertHasOnlyKeys($expected, ['commandName']); if (isset($expected->commandName)) { diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 7f403d680..026574e19 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -7,6 +7,7 @@ use MongoDB\Client; use MongoDB\Collection; use MongoDB\Database; +use MongoDB\Driver\Cursor; use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\GridFS\Bucket; @@ -35,6 +36,7 @@ use function PHPUnit\Framework\assertFalse; use function PHPUnit\Framework\assertInstanceOf; use function PHPUnit\Framework\assertIsArray; +use function PHPUnit\Framework\assertIsInt; use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertMatchesRegularExpression; @@ -81,6 +83,9 @@ final class Operation /** @var ExpectedResult */ private $expectedResult; + /** @var bool */ + private $ignoreResultAndError; + /** @var string */ private $saveResultAsEntity; @@ -101,10 +106,15 @@ public function __construct(stdClass $o, Context $context) $this->arguments = (array) $o->arguments; } + if (isset($o->ignoreResultAndError) && (isset($o->expectError) || property_exists($o, 'expectResult') || isset($o->saveResultAsEntity))) { + Assert::fail('ignoreResultAndError is mutually exclusive with expectError, expectResult, and saveResultAsEntity'); + } + if (isset($o->expectError) && (property_exists($o, 'expectResult') || isset($o->saveResultAsEntity))) { Assert::fail('expectError is mutually exclusive with expectResult and saveResultAsEntity'); } + $this->ignoreResultAndError = $o->ignoreResultAndError ?? false; $this->expectError = new ExpectedError($o->expectError ?? null, $this->entityMap); $this->expectResult = new ExpectedResult($o, $this->entityMap, $this->object); @@ -158,8 +168,10 @@ public function assert(bool $rethrowExceptions = false) } } - $this->expectError->assert($error); - $this->expectResult->assert($result, $saveResultAsEntity); + if (! $this->ignoreResultAndError) { + $this->expectError->assert($error); + $this->expectResult->assert($result, $saveResultAsEntity); + } // Rethrowing is primarily used for withTransaction callbacks if ($error && $rethrowExceptions) { @@ -193,6 +205,9 @@ private function execute() case ChangeStream::class: $result = $this->executeForChangeStream($object); break; + case Cursor::class: + $result = $this->executeForCursor($object); + break; case Session::class: $result = $this->executeForSession($object); break; @@ -276,6 +291,11 @@ private function executeForCollection(Collection $collection) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); + case 'createFindCursor': + return $collection->find( + $args['filter'], + array_diff_key($args, ['filter' => 1]) + ); case 'createIndex': return $collection->createIndex( $args['keys'], @@ -384,6 +404,52 @@ private function executeForCollection(Collection $collection) } } + private function executeForCursor(Cursor $cursor) + { + $args = $this->prepareArguments(); + + switch ($this->name) { + case 'close': + /* PHPC does not provide an API to directly close a cursor. + * mongoc_cursor_destroy is only invoked from the Cursor's + * free_object handler, which requires unsetting the object from + * the entity map to trigger garbage collection. This will need + * a different approach if tests ever attempt to access the + * cursor entity after calling the "close" operation. */ + $this->entityMap->closeCursor($this->object); + assertFalse($this->entityMap->offsetExists($this->object)); + break; + case 'iterateUntilDocumentOrError': + /* Note: the first iteration should use rewind, otherwise we may + * miss a document from the initial batch (possible if using a + * resume token). We can infer this from a null key; however, + * if a test ever calls this operation consecutively to expect + * multiple errors from the same ChangeStream we will need a + * different approach (e.g. examining internal hasAdvanced + * property on the ChangeStream). */ + + /* Note: similar to iterateUntilDocumentOrError for ChangeStream + * entities, a different approach will be needed if a test ever + * calls this operation consecutively to expect multiple errors. + */ + if ($cursor->key() === null) { + $cursor->rewind(); + + if ($cursor->valid()) { + return $cursor->current(); + } + } + + do { + $cursor->next(); + } while (! $cursor->valid()); + + return $cursor->current(); + default: + Assert::fail('Unsupported cursor operation: ' . $this->name); + } + } + private function executeForDatabase(Database $database) { $args = $this->prepareArguments(); @@ -532,6 +598,13 @@ private function executeForTestRunner() $eventObserver = $this->context->getEventObserverForClient($this->arguments['client']); assertNotEquals(...$eventObserver->getLsidsOnLastTwoCommands()); break; + case 'assertNumberConnectionsCheckedOut': + assertIsInt($args['connections']); + /* PHP does not implement connection pooling. Check parameters + * for the sake of valid-fail tests, but otherwise raise an + * error. */ + Assert::fail('Tests using assertNumberConnectionsCheckedOut should be skipped'); + break; case 'assertSessionDirty': assertTrue($this->context->isDirtySession($this->arguments['session'])); break; diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index 0c372e03d..5fe6c0314 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -4,8 +4,10 @@ use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use stdClass; +use function array_diff; use function in_array; use function PHPUnit\Framework\assertContainsOnly; +use function PHPUnit\Framework\assertEmpty; use function PHPUnit\Framework\assertIsArray; use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; @@ -18,6 +20,7 @@ class RunOnRequirement const TOPOLOGY_REPLICASET = 'replicaset'; const TOPOLOGY_SHARDED = 'sharded'; const TOPOLOGY_SHARDED_REPLICASET = 'sharded-replicaset'; + const TOPOLOGY_LOAD_BALANCED = 'load-balanced'; const VERSION_PATTERN = '/^[0-9]+(\\.[0-9]+){1,2}$/'; @@ -33,8 +36,22 @@ class RunOnRequirement /** @var stdClass */ private $serverParameters; + /** @var bool */ + private $auth; + + /** @var array */ + private static $supportedTopologies = [ + self::TOPOLOGY_SINGLE, + self::TOPOLOGY_REPLICASET, + self::TOPOLOGY_SHARDED, + self::TOPOLOGY_SHARDED_REPLICASET, + self::TOPOLOGY_LOAD_BALANCED, + ]; + public function __construct(stdClass $o) { + Util::assertHasOnlyKeys($o, ['minServerVersion', 'maxServerVersion', 'topologies', 'serverParameters', 'auth']); + if (isset($o->minServerVersion)) { assertIsString($o->minServerVersion); assertMatchesRegularExpression(self::VERSION_PATTERN, $o->minServerVersion); @@ -50,6 +67,7 @@ public function __construct(stdClass $o) if (isset($o->topologies)) { assertIsArray($o->topologies); assertContainsOnly('string', $o->topologies); + assertEmpty(array_diff($o->topologies, self::$supportedTopologies)); $this->topologies = $o->topologies; } @@ -57,9 +75,14 @@ public function __construct(stdClass $o) assertIsObject($o->serverParameters); $this->serverParameters = $o->serverParameters; } + + if (isset($o->auth)) { + assertIsBool($o->auth); + $this->auth = $o->auth; + } } - public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters) : bool + public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated) : bool { if (isset($this->minServerVersion) && version_compare($serverVersion, $this->minServerVersion, '<')) { return false; @@ -90,6 +113,10 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s } } + if (isset($this->auth) && $isAuthenticated !== $this->auth) { + return false; + } + return true; } } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index c53ae256a..b18684f1b 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -42,6 +42,11 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', + // PHPC does not implement CMAP + 'valid-pass/assertNumberConnectionsCheckedOut: basic assertion succeeds' => 'PHPC does not implement CMAP', + 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', + 'valid-pass/expectedEventsForClient-eventType: eventType can be set to command and cmap' => 'PHPC does not implement CMAP', + 'valid-pass/expectedEventsForClient-eventType: eventType defaults to command if unset' => 'PHPC does not implement CMAP', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index a55697f60..ea5e0b2da 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -6,6 +6,7 @@ use MongoDB\Driver\Exception\ServerException; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; +use MongoDB\Model\BSONArray; use MongoDB\Operation\DatabaseCommand; use MongoDB\Tests\FunctionalTestCase; use PHPUnit\Framework\Assert; @@ -16,6 +17,7 @@ use Throwable; use UnexpectedValueException; use function call_user_func; +use function count; use function gc_collect_cycles; use function in_array; use function is_string; @@ -43,7 +45,7 @@ final class UnifiedTestRunner const SERVER_ERROR_UNAUTHORIZED = 13; const MIN_SCHEMA_VERSION = '1.0'; - const MAX_SCHEMA_VERSION = '1.2'; + const MAX_SCHEMA_VERSION = '1.3'; /** @var MongoDB\Client */ private $internalClient; @@ -213,93 +215,40 @@ private function doTestCase(stdClass $test, string $schemaVersion, array $runOnR /** * Checks server version and topology requirements. * + * Arguments for RunOnRequirement::isSatisfied() will be cached internally. + * * @throws SkippedTest unless one or more runOnRequirements are met */ private function checkRunOnRequirements(array $runOnRequirements) { + static $cachedIsSatisfiedArgs; + assertNotEmpty($runOnRequirements); assertContainsOnly('object', $runOnRequirements); - $serverVersion = $this->getCachedServerVersion(); - $topology = $this->getCachedTopology(); - $serverParameters = $this->getCachedServerParameters(); + if (! isset($cachedIsSatisfiedArgs)) { + $cachedIsSatisfiedArgs = [ + $this->getServerVersion(), + $this->getTopology(), + $this->getServerParameters(), + $this->isAuthenticated(), + ]; + } foreach ($runOnRequirements as $o) { $runOnRequirement = new RunOnRequirement($o); - if ($runOnRequirement->isSatisfied($serverVersion, $topology, $serverParameters)) { + if ($runOnRequirement->isSatisfied(...$cachedIsSatisfiedArgs)) { return; } } // @todo Add server parameter requirements? - Assert::markTestSkipped(sprintf('Server version "%s" and topology "%s" do not meet test requirements', $serverVersion, $topology)); - } - - /** - * Return the server parameters (cached for subsequent calls). - */ - private function getCachedServerParameters() : stdClass - { - static $cachedServerParameters; - - if (isset($cachedServerParameters)) { - return $cachedServerParameters; - } - - $cachedServerParameters = $this->getServerParameters(); - - return $cachedServerParameters; - } - - /** - * Return the server version (cached for subsequent calls). - */ - private function getCachedServerVersion() : string - { - static $cachedServerVersion; - - if (isset($cachedServerVersion)) { - return $cachedServerVersion; - } - - $cachedServerVersion = $this->getServerVersion(); - - return $cachedServerVersion; - } - - /** - * Return the topology type (cached for subsequent calls). - * - * @throws UnexpectedValueException if topology is neither single nor RS nor sharded - */ - private function getCachedTopology() : string - { - static $cachedTopology = null; - - if (isset($cachedTopology)) { - return $cachedTopology; - } - - switch ($this->getPrimaryServer()->getType()) { - case Server::TYPE_STANDALONE: - $cachedTopology = RunOnRequirement::TOPOLOGY_SINGLE; - break; - - case Server::TYPE_RS_PRIMARY: - $cachedTopology = RunOnRequirement::TOPOLOGY_REPLICASET; - break; - - case Server::TYPE_MONGOS: - $cachedTopology = $this->isShardedClusterUsingReplicasets() - ? RunOnRequirement::TOPOLOGY_SHARDED_REPLICASET - : RunOnRequirement::TOPOLOGY_SHARDED; - break; - - default: - throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); - } - - return $cachedTopology; + Assert::markTestSkipped(sprintf( + 'Server (version=%s, toplogy=%s, auth=%s) does not meet test requirements', + $cachedIsSatisfiedArgs[0], + $cachedIsSatisfiedArgs[1], + $cachedIsSatisfiedArgs[3] ? 'yes' : 'no' + )); } private function getPrimaryServer() : Server @@ -339,6 +288,47 @@ private function getServerVersion() : string throw new UnexpectedValueException('Could not determine server version'); } + /** + * Return the topology type. + * + * @throws UnexpectedValueException if topology is neither single nor RS nor sharded + */ + private function getTopology() : string + { + // TODO: detect load-balanced topologies once PHPLIB-671 is implemented + switch ($this->getPrimaryServer()->getType()) { + case Server::TYPE_STANDALONE: + return RunOnRequirement::TOPOLOGY_SINGLE; + case Server::TYPE_RS_PRIMARY: + return RunOnRequirement::TOPOLOGY_REPLICASET; + case Server::TYPE_MONGOS: + return $this->isShardedClusterUsingReplicasets() + ? RunOnRequirement::TOPOLOGY_SHARDED_REPLICASET + : RunOnRequirement::TOPOLOGY_SHARDED; + default: + throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); + } + } + + /** + * Return whether the connection is authenticated. + * + * Note: if the connectionStatus command is not portable for serverless, it + * may be necessary to rewrite this to instead inspect the connection string + * or consult an environment variable, as is done in libmongoc. + */ + private function isAuthenticated() : bool + { + $database = $this->internalClient->selectDatabase('admin'); + $connectionStatus = $database->command(['connectionStatus' => 1])->toArray()[0]; + + if (isset($connectionStatus->authInfo->authenticatedUsers) && $connectionStatus->authInfo->authenticatedUsers instanceof BSONArray) { + return count($connectionStatus->authInfo->authenticatedUsers) > 0; + } + + throw new UnexpectedValueException('Could not determine authentication status'); + } + /** * Checks is a test format schema version is supported. */ diff --git a/tests/UnifiedSpecTests/valid-fail/assertNumberConnectionsCheckedOut.json b/tests/UnifiedSpecTests/valid-fail/assertNumberConnectionsCheckedOut.json new file mode 100644 index 000000000..9799bb2f6 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/assertNumberConnectionsCheckedOut.json @@ -0,0 +1,63 @@ +{ + "description": "assertNumberConnectionsCheckedOut", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + } + ], + "tests": [ + { + "description": "operation fails if client field is not specified", + "operations": [ + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "connections": 1 + } + } + ] + }, + { + "description": "operation fails if connections field is not specified", + "operations": [ + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ] + }, + { + "description": "operation fails if client entity does not exist", + "operations": [ + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client1" + } + } + ] + }, + { + "description": "operation fails if number of connections is incorrect", + "operations": [ + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json b/tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json new file mode 100644 index 000000000..f4c5bcdf4 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json @@ -0,0 +1,62 @@ +{ + "description": "entity-find-cursor", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "databaseName": "database0Name", + "collectionName": "coll0", + "documents": [] + } + ], + "tests": [ + { + "description": "createFindCursor fails if filter is not specified", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "saveResultAsEntity": "cursor0" + } + ] + }, + { + "description": "iterateUntilDocumentOrError fails if it references a nonexistent entity", + "operations": [ + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0" + } + ] + }, + { + "description": "close fails if it references a nonexistent entity", + "operations": [ + { + "name": "close", + "object": "cursor0" + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json b/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json new file mode 100644 index 000000000..4457040b4 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json @@ -0,0 +1,72 @@ +{ + "description": "ignoreResultAndError", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "operation errors are not ignored if ignoreResultAndError is false", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + }, + "ignoreResultAndError": false + } + ] + }, + { + "description": "malformed operation fails if ignoreResultAndError is true", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "foo": "bar" + }, + "ignoreResultAndError": true + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/assertNumberConnectionsCheckedOut.json b/tests/UnifiedSpecTests/valid-pass/assertNumberConnectionsCheckedOut.json new file mode 100644 index 000000000..a9fc063f3 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/assertNumberConnectionsCheckedOut.json @@ -0,0 +1,27 @@ +{ + "description": "assertNumberConnectionsCheckedOut", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + } + ], + "tests": [ + { + "description": "basic assertion succeeds", + "operations": [ + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/entity-client-cmap-events.json b/tests/UnifiedSpecTests/valid-pass/entity-client-cmap-events.json new file mode 100644 index 000000000..3209033de --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/entity-client-cmap-events.json @@ -0,0 +1,71 @@ +{ + "description": "entity-client-cmap-events", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "connectionReadyEvent", + "connectionCheckedOutEvent", + "connectionCheckedInEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "events are captured during an operation", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json b/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json new file mode 100644 index 000000000..85b8f69d7 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json @@ -0,0 +1,182 @@ +{ + "description": "entity-find-cursor", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "databaseName": "database0Name", + "collectionName": "coll0", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + }, + { + "_id": 4 + }, + { + "_id": 5 + } + ] + } + ], + "tests": [ + { + "description": "cursors can be created, iterated, and closed", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 2 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 3 + } + }, + { + "name": "close", + "object": "cursor0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find", + "databaseName": "database0Name" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "ns": { + "$$type": "string" + }, + "firstBatch": { + "$$type": "array" + } + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "ns": { + "$$type": "string" + }, + "nextBatch": { + "$$type": "array" + } + } + }, + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "command": { + "killCursors": "coll0", + "cursors": { + "$$type": "array" + } + }, + "commandName": "killCursors" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursorsKilled": { + "$$unsetOrMatches": { + "$$type": "array" + } + } + }, + "commandName": "killCursors" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-eventType.json b/tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-eventType.json new file mode 100644 index 000000000..fe308df96 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-eventType.json @@ -0,0 +1,126 @@ +{ + "description": "expectedEventsForClient-eventType", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent", + "connectionReadyEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "eventType can be set to command and cmap", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "eventType": "command", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1 + } + ] + }, + "commandName": "insert" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + } + ] + } + ] + }, + { + "description": "eventType defaults to command if unset", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1 + } + ] + }, + "commandName": "insert" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/ignoreResultAndError.json b/tests/UnifiedSpecTests/valid-pass/ignoreResultAndError.json new file mode 100644 index 000000000..2e9b1c58a --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/ignoreResultAndError.json @@ -0,0 +1,59 @@ +{ + "description": "ignoreResultAndError", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "operation errors are ignored if ignoreResultAndError is true", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + }, + "ignoreResultAndError": true + } + ] + } + ] +} From 3f5de670f30af99b27ae5ef36066c7e2fb441343 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 16:35:01 -0400 Subject: [PATCH 055/321] PHPLIB-679: Check presence and type of operation args Explicit assertions can avoid differing behavior for undefined array keys (notice/warning on PHP 7/8, respectively). --- tests/UnifiedSpecTests/Operation.php | 140 ++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 1 deletion(-) diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 026574e19..64015062f 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\UnifiedSpecTests; use Error; +use MongoDB\BSON\Javascript; use MongoDB\ChangeStream; use MongoDB\Client; use MongoDB\Collection; @@ -17,6 +18,7 @@ use MongoDB\Operation\FindOneAndUpdate; use PHPUnit\Framework\Assert; use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\Constraint\IsType; use stdClass; use Throwable; use function array_diff_key; @@ -30,6 +32,7 @@ use function iterator_to_array; use function key; use function MongoDB\with_transaction; +use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertContains; use function PHPUnit\Framework\assertCount; use function PHPUnit\Framework\assertEquals; @@ -258,6 +261,9 @@ private function executeForClient(Client $client) switch ($this->name) { case 'createChangeStream': + assertArrayHasKey('pipeline', $args); + assertIsArray($args['pipeline']); + return $client->watch( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) @@ -277,37 +283,58 @@ private function executeForCollection(Collection $collection) switch ($this->name) { case 'aggregate': + assertArrayHasKey('pipeline', $args); + assertIsArray($args['pipeline']); + return iterator_to_array($collection->aggregate( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) )); case 'bulkWrite': + assertArrayHasKey('requests', $args); + assertIsArray($args['requests']); + return $collection->bulkWrite( array_map('self::prepareBulkWriteRequest', $args['requests']), array_diff_key($args, ['requests' => 1]) ); case 'createChangeStream': + assertArrayHasKey('pipeline', $args); + assertIsArray($args['pipeline']); + return $collection->watch( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); case 'createFindCursor': + assertArrayHasKey('filter', $args); + assertInstanceOf(stdClass::class, $args['filter']); + return $collection->find( $args['filter'], array_diff_key($args, ['filter' => 1]) ); case 'createIndex': + assertArrayHasKey('keys', $args); + assertInstanceOf(stdClass::class, $args['keys']); + return $collection->createIndex( $args['keys'], array_diff_key($args, ['keys' => 1]) ); case 'dropIndex': + assertArrayHasKey('name', $args); + assertIsString($args['name']); + return $collection->dropIndex( $args['name'], array_diff_key($args, ['name' => 1]) ); case 'count': case 'countDocuments': + assertArrayHasKey('filter', $args); + assertInstanceOf(stdClass::class, $args['filter']); + return $collection->{$this->name}( $args['filter'], array_diff_key($args, ['filter' => 1]) @@ -317,6 +344,9 @@ private function executeForCollection(Collection $collection) case 'deleteMany': case 'deleteOne': case 'findOneAndDelete': + assertArrayHasKey('filter', $args); + assertInstanceOf(stdClass::class, $args['filter']); + return $collection->{$this->name}( $args['filter'], array_diff_key($args, ['filter' => 1]) @@ -327,6 +357,11 @@ private function executeForCollection(Collection $collection) $collection->distinct('foo'); } + assertArrayHasKey('fieldName', $args); + assertArrayHasKey('filter', $args); + assertIsString($args['fieldName']); + assertInstanceOf(stdClass::class, $args['filter']); + return $collection->distinct( $args['fieldName'], $args['filter'], @@ -335,12 +370,21 @@ private function executeForCollection(Collection $collection) case 'drop': return $collection->drop($args); case 'find': + assertArrayHasKey('filter', $args); + assertInstanceOf(stdClass::class, $args['filter']); + return iterator_to_array($collection->find( $args['filter'], array_diff_key($args, ['filter' => 1]) )); case 'findOne': - return $collection->findOne($args['filter'], array_diff_key($args, ['filter' => 1])); + assertArrayHasKey('filter', $args); + assertInstanceOf(stdClass::class, $args['filter']); + + return $collection->findOne( + $args['filter'], + array_diff_key($args, ['filter' => 1]) + ); case 'findOneAndReplace': if (isset($args['returnDocument'])) { $args['returnDocument'] = strtolower($args['returnDocument']); @@ -353,6 +397,11 @@ private function executeForCollection(Collection $collection) // Fall through case 'replaceOne': + assertArrayHasKey('filter', $args); + assertArrayHasKey('replacement', $args); + assertInstanceOf(stdClass::class, $args['filter']); + assertInstanceOf(stdClass::class, $args['replacement']); + return $collection->{$this->name}( $args['filter'], $args['replacement'], @@ -371,6 +420,11 @@ private function executeForCollection(Collection $collection) case 'updateMany': case 'updateOne': + assertArrayHasKey('filter', $args); + assertArrayHasKey('update', $args); + assertInstanceOf(stdClass::class, $args['filter']); + assertThat($args['update'], logicalOr(new IsType('array'), new IsType('object'))); + return $collection->{$this->name}( $args['filter'], $args['update'], @@ -381,11 +435,17 @@ private function executeForCollection(Collection $collection) $options = isset($args['options']) ? (array) $args['options'] : []; $options += array_diff_key($args, ['documents' => 1]); + assertArrayHasKey('documents', $args); + assertIsArray($args['documents']); + return $collection->insertMany( $args['documents'], $options ); case 'insertOne': + assertArrayHasKey('document', $args); + assertInstanceOf(stdClass::class, $args['document']); + return $collection->insertOne( $args['document'], array_diff_key($args, ['document' => 1]) @@ -393,6 +453,13 @@ private function executeForCollection(Collection $collection) case 'listIndexes': return iterator_to_array($collection->listIndexes($args)); case 'mapReduce': + assertArrayHasKey('map', $args); + assertArrayHasKey('reduce', $args); + assertArrayHasKey('out', $args); + assertInstanceOf(Javascript::class, $args['map']); + assertInstanceOf(Javascript::class, $args['reduce']); + assertIsString($args['out']); + return $collection->mapReduce( $args['map'], $args['reduce'], @@ -456,21 +523,33 @@ private function executeForDatabase(Database $database) switch ($this->name) { case 'aggregate': + assertArrayHasKey('pipeline', $args); + assertIsArray($args['pipeline']); + return iterator_to_array($database->aggregate( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) )); case 'createChangeStream': + assertArrayHasKey('pipeline', $args); + assertIsArray($args['pipeline']); + return $database->watch( $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); case 'createCollection': + assertArrayHasKey('collection', $args); + assertIsString($args['collection']); + return $database->createCollection( $args['collection'], array_diff_key($args, ['collection' => 1]) ); case 'dropCollection': + assertArrayHasKey('collection', $args); + assertIsString($args['collection']); + return $database->dropCollection( $args['collection'], array_diff_key($args, ['collection' => 1]) @@ -480,6 +559,9 @@ private function executeForDatabase(Database $database) case 'listCollections': return iterator_to_array($database->listCollections($args)); case 'runCommand': + assertArrayHasKey('command', $args); + assertInstanceOf(stdClass::class, $args['command']); + return $database->command( $args['command'], array_diff_key($args, ['command' => 1]) @@ -503,6 +585,7 @@ private function executeForSession(Session $session) case 'startTransaction': return $session->startTransaction($args); case 'withTransaction': + assertArrayHasKey('callback', $args); assertIsArray($args['callback']); $operations = array_map(function ($o) { @@ -529,15 +612,23 @@ private function executeForBucket(Bucket $bucket) switch ($this->name) { case 'delete': + assertArrayHasKey('id', $args); + return $bucket->delete($args['id']); case 'downloadByName': + assertArrayHasKey('filename', $args); + assertIsString($args['filename']); + return stream_get_contents($bucket->openDownloadStreamByName( $args['filename'], array_diff_key($args, ['filename' => 1]) )); case 'download': + assertArrayHasKey('id', $args); + return stream_get_contents($bucket->openDownloadStream($args['id'])); case 'uploadWithId': + assertArrayHasKey('id', $args); $args['_id'] = $args['id']; unset($args['id']); @@ -567,38 +658,55 @@ private function executeForTestRunner() switch ($this->name) { case 'assertCollectionExists': + assertArrayHasKey('databaseName', $args); + assertArrayHasKey('collectionName', $args); assertIsString($args['databaseName']); assertIsString($args['collectionName']); $database = $this->context->getInternalClient()->selectDatabase($args['databaseName']); assertContains($args['collectionName'], $database->listCollectionNames()); break; case 'assertCollectionNotExists': + assertArrayHasKey('databaseName', $args); + assertArrayHasKey('collectionName', $args); assertIsString($args['databaseName']); assertIsString($args['collectionName']); $database = $this->context->getInternalClient()->selectDatabase($args['databaseName']); assertNotContains($args['collectionName'], $database->listCollectionNames()); break; case 'assertIndexExists': + assertArrayHasKey('databaseName', $args); + assertArrayHasKey('collectionName', $args); + assertArrayHasKey('indexName', $args); assertIsString($args['databaseName']); assertIsString($args['collectionName']); assertIsString($args['indexName']); assertContains($args['indexName'], $this->getIndexNames($args['databaseName'], $args['collectionName'])); break; case 'assertIndexNotExists': + assertArrayHasKey('databaseName', $args); + assertArrayHasKey('collectionName', $args); + assertArrayHasKey('indexName', $args); assertIsString($args['databaseName']); assertIsString($args['collectionName']); assertIsString($args['indexName']); assertNotContains($args['indexName'], $this->getIndexNames($args['databaseName'], $args['collectionName'])); break; case 'assertSameLsidOnLastTwoCommands': + /* Context::getEventObserverForClient() requires the client ID. + * Avoid checking $args['client'], which is already resolved. */ + assertArrayHasKey('client', $this->arguments); $eventObserver = $this->context->getEventObserverForClient($this->arguments['client']); assertEquals(...$eventObserver->getLsidsOnLastTwoCommands()); break; case 'assertDifferentLsidOnLastTwoCommands': + /* Context::getEventObserverForClient() requires the client ID. + * Avoid checking $args['client'], which is already resolved. */ + assertArrayHasKey('client', $this->arguments); $eventObserver = $this->context->getEventObserverForClient($this->arguments['client']); assertNotEquals(...$eventObserver->getLsidsOnLastTwoCommands()); break; case 'assertNumberConnectionsCheckedOut': + assertArrayHasKey('connections', $args); assertIsInt($args['connections']); /* PHP does not implement connection pooling. Check parameters * for the sake of valid-fail tests, but otherwise raise an @@ -606,28 +714,42 @@ private function executeForTestRunner() Assert::fail('Tests using assertNumberConnectionsCheckedOut should be skipped'); break; case 'assertSessionDirty': + /* Context::isDirtySession() requires the session ID. Avoid + * checking $args['session'], which is already resolved. */ + assertArrayHasKey('session', $this->arguments); assertTrue($this->context->isDirtySession($this->arguments['session'])); break; case 'assertSessionNotDirty': + /* Context::isDirtySession() requires the session ID. Avoid + * checking $args['session'], which is already resolved. */ + assertArrayHasKey('session', $this->arguments); assertFalse($this->context->isDirtySession($this->arguments['session'])); break; case 'assertSessionPinned': + assertArrayHasKey('session', $args); assertInstanceOf(Session::class, $args['session']); assertInstanceOf(Server::class, $args['session']->getServer()); break; case 'assertSessionTransactionState': + assertArrayHasKey('session', $args); assertInstanceOf(Session::class, $args['session']); assertSame($this->arguments['state'], $args['session']->getTransactionState()); break; case 'assertSessionUnpinned': + assertArrayHasKey('session', $args); assertInstanceOf(Session::class, $args['session']); assertNull($args['session']->getServer()); break; case 'failPoint': + assertArrayHasKey('client', $args); + assertArrayHasKey('failPoint', $args); + assertInstanceOf(Client::class, $args['client']); assertInstanceOf(stdClass::class, $args['failPoint']); $args['client']->selectDatabase('admin')->command($args['failPoint']); break; case 'targetedFailPoint': + assertArrayHasKey('session', $args); + assertArrayHasKey('failPoint', $args); assertInstanceOf(Session::class, $args['session']); assertInstanceOf(stdClass::class, $args['failPoint']); assertNotNull($args['session']->getServer(), 'Session is pinned'); @@ -635,6 +757,7 @@ private function executeForTestRunner() $operation->execute($args['session']->getServer()); break; case 'loop': + assertArrayHasKey('operations', $args); assertIsArray($args['operations']); $operations = array_map(function ($o) { @@ -685,6 +808,9 @@ private static function prepareBulkWriteRequest(stdClass $request) : array switch ($type) { case 'deleteMany': case 'deleteOne': + assertArrayHasKey('filter', $args); + assertInstanceOf(stdClass::class, $args['filter']); + return [ $type => [ $args['filter'], @@ -692,8 +818,15 @@ private static function prepareBulkWriteRequest(stdClass $request) : array ], ]; case 'insertOne': + assertArrayHasKey('document', $args); + return [ 'insertOne' => [ $args['document']]]; case 'replaceOne': + assertArrayHasKey('filter', $args); + assertArrayHasKey('replacement', $args); + assertInstanceOf(stdClass::class, $args['filter']); + assertInstanceOf(stdClass::class, $args['replacement']); + return [ 'replaceOne' => [ $args['filter'], @@ -703,6 +836,11 @@ private static function prepareBulkWriteRequest(stdClass $request) : array ]; case 'updateMany': case 'updateOne': + assertArrayHasKey('filter', $args); + assertArrayHasKey('update', $args); + assertInstanceOf(stdClass::class, $args['filter']); + assertThat($args['update'], logicalOr(new IsType('array'), new IsType('object'))); + return [ $type => [ $args['filter'], From bf9978faf11abc7073483c59db00a3d507371ef8 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 16:37:29 -0400 Subject: [PATCH 056/321] Resolve "client" operation arg as a common option This is presently only used for test runner ops, but the spec does define it as a common option that should always be resolved (like "session"). --- tests/UnifiedSpecTests/Operation.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 64015062f..9c169fd60 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -651,11 +651,6 @@ private function executeForTestRunner() { $args = $this->prepareArguments(); - if (array_key_exists('client', $args)) { - assertIsString($args['client']); - $args['client'] = $this->entityMap->getClient($args['client']); - } - switch ($this->name) { case 'assertCollectionExists': assertArrayHasKey('databaseName', $args); @@ -786,6 +781,11 @@ private function prepareArguments() : array { $args = $this->arguments; + if (array_key_exists('client', $args)) { + assertIsString($args['client']); + $args['client'] = $this->entityMap->getClient($args['client']); + } + if (array_key_exists('session', $args)) { assertIsString($args['session']); $args['session'] = $this->entityMap->getSession($args['session']); From dd9ce1c45285efbcb40447b580b82948888c9ef4 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 17:27:04 -0400 Subject: [PATCH 057/321] PHPLIB-680: Topology match should not preempt later checks --- tests/UnifiedSpecTests/RunOnRequirement.php | 27 ++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index 5fe6c0314..1ddf0b927 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -92,17 +92,7 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s return false; } - if (isset($this->topologies)) { - if (in_array($topology, $this->topologies)) { - return true; - } - - /* Ensure "sharded-replicaset" is also accepted for topologies that - * only include "sharded" (agnostic about the shard topology) */ - if ($topology === self::TOPOLOGY_SHARDED_REPLICASET && in_array(self::TOPOLOGY_SHARDED, $this->topologies)) { - return true; - } - + if (isset($this->topologies) && ! $this->isTopologySatisfied($topology)) { return false; } @@ -119,4 +109,19 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s return true; } + + private function isTopologySatisfied(string $topology) : bool + { + if (in_array($topology, $this->topologies)) { + return true; + } + + /* Ensure "sharded-replicaset" is also accepted for topologies that + * only include "sharded" (agnostic about the shard topology) */ + if ($topology === self::TOPOLOGY_SHARDED_REPLICASET && in_array(self::TOPOLOGY_SHARDED, $this->topologies)) { + return true; + } + + return false; + } } From fca066ec89d72ba70421164b77b776e7afb74dd8 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 5 Jul 2021 17:36:01 -0400 Subject: [PATCH 058/321] PHPLIB-670: Unified test runner changes for serverless support Sync unified transaction tests with mongodb/specifications@ba8a3f7587f1330cd7ca476371ac92c176152c1c Detection of serverless will be addressed after driver support is implemented (PHPC-1755) --- tests/UnifiedSpecTests/RunOnRequirement.php | 35 ++++++++- tests/UnifiedSpecTests/UnifiedTestRunner.php | 12 +++- .../transactions/mongos-unpin.json | 72 +++++++++++++++++-- 3 files changed, 112 insertions(+), 7 deletions(-) diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index 1ddf0b927..4fd46f6e3 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -6,6 +6,7 @@ use stdClass; use function array_diff; use function in_array; +use function PHPUnit\Framework\assertContains; use function PHPUnit\Framework\assertContainsOnly; use function PHPUnit\Framework\assertEmpty; use function PHPUnit\Framework\assertIsArray; @@ -22,6 +23,10 @@ class RunOnRequirement const TOPOLOGY_SHARDED_REPLICASET = 'sharded-replicaset'; const TOPOLOGY_LOAD_BALANCED = 'load-balanced'; + const SERVERLESS_REQUIRE = 'require'; + const SERVERLESS_FORBID = 'forbid'; + const SERVERLESS_ALLOW = 'allow'; + const VERSION_PATTERN = '/^[0-9]+(\\.[0-9]+){1,2}$/'; /** @var string */ @@ -39,6 +44,9 @@ class RunOnRequirement /** @var bool */ private $auth; + /** @var string */ + private $serverless; + /** @var array */ private static $supportedTopologies = [ self::TOPOLOGY_SINGLE, @@ -48,9 +56,16 @@ class RunOnRequirement self::TOPOLOGY_LOAD_BALANCED, ]; + /** @var array */ + private static $supportedServerless = [ + self::SERVERLESS_REQUIRE, + self::SERVERLESS_FORBID, + self::SERVERLESS_ALLOW, + ]; + public function __construct(stdClass $o) { - Util::assertHasOnlyKeys($o, ['minServerVersion', 'maxServerVersion', 'topologies', 'serverParameters', 'auth']); + Util::assertHasOnlyKeys($o, ['minServerVersion', 'maxServerVersion', 'topologies', 'serverParameters', 'auth', 'serverless']); if (isset($o->minServerVersion)) { assertIsString($o->minServerVersion); @@ -80,9 +95,15 @@ public function __construct(stdClass $o) assertIsBool($o->auth); $this->auth = $o->auth; } + + if (isset($o->serverless)) { + assertIsString($o->serverless); + assertContains($o->serverless, self::$supportedServerless); + $this->serverless = $o->serverless; + } } - public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated) : bool + public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated, bool $isServerless) : bool { if (isset($this->minServerVersion) && version_compare($serverVersion, $this->minServerVersion, '<')) { return false; @@ -107,6 +128,16 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s return false; } + if (isset($this->serverless)) { + if (! $isServerless && $this->serverless === self::SERVERLESS_REQUIRE) { + return false; + } + + if ($isServerless && $this->serverless === self::SERVERLESS_FORBID) { + return false; + } + } + return true; } diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index ea5e0b2da..d30a7d6ec 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -45,7 +45,7 @@ final class UnifiedTestRunner const SERVER_ERROR_UNAUTHORIZED = 13; const MIN_SCHEMA_VERSION = '1.0'; - const MAX_SCHEMA_VERSION = '1.3'; + const MAX_SCHEMA_VERSION = '1.4'; /** @var MongoDB\Client */ private $internalClient; @@ -232,6 +232,7 @@ private function checkRunOnRequirements(array $runOnRequirements) $this->getTopology(), $this->getServerParameters(), $this->isAuthenticated(), + $this->isServerless(), ]; } @@ -329,6 +330,15 @@ private function isAuthenticated() : bool throw new UnexpectedValueException('Could not determine authentication status'); } + /** + * Return whether serverless (i.e. proxy as mongos) is being utilized. + */ + private function isServerless() : bool + { + // TODO: detect serverless once PHPC-1755 is implemented + return false; + } + /** * Checks is a test format schema version is supported. */ diff --git a/tests/UnifiedSpecTests/transactions/mongos-unpin.json b/tests/UnifiedSpecTests/transactions/mongos-unpin.json index 33127198a..4f7ae4379 100644 --- a/tests/UnifiedSpecTests/transactions/mongos-unpin.json +++ b/tests/UnifiedSpecTests/transactions/mongos-unpin.json @@ -1,6 +1,6 @@ { "description": "mongos-unpin", - "schemaVersion": "1.1", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "4.2", @@ -49,7 +49,12 @@ }, "tests": [ { - "description": "unpin after TransientTransctionError error on commit", + "description": "unpin after TransientTransactionError error on commit", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "operations": [ { "name": "startTransaction", @@ -103,6 +108,24 @@ "arguments": { "session": "session0" } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" } ] }, @@ -137,7 +160,12 @@ ] }, { - "description": "unpin after TransientTransctionError error on abort", + "description": "unpin after non-transient error on abort", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "operations": [ { "name": "startTransaction", @@ -182,11 +210,29 @@ "arguments": { "session": "session0" } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" } ] }, { - "description": "unpin after non-transient error on abort", + "description": "unpin after TransientTransactionError error on abort", "operations": [ { "name": "startTransaction", @@ -231,6 +277,24 @@ "arguments": { "session": "session0" } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" } ] }, From 903e101d2e498d432a56b5fa97aeb709a57d036e Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 7 Jul 2021 13:07:46 +0200 Subject: [PATCH 059/321] PHPLIB-674 Revise documentation for installing coding standard (#838) * Remove workaround due to doctrine/coding-standard being incompatible * Update to doctrine/coding-standard 9.0 and phpcs 3.6 * phpcbf: fix SlevomatCodingStandard.TypeHints.ReturnTypeHintSpacing PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/Operation/FunctionalTestCase.php 2 0 src/Operation/ListCollectionNames.php 1 0 tests/GridFS/FunctionalTestCase.php 1 0 tests/Operation/DeleteFunctionalTest.php 1 0 tests/ClientFunctionalTest.php 1 0 tests/UnifiedSpecTests/Util.php 4 0 src/GridFS/Exception/StreamException.php 3 0 tests/Operation/InsertManyFunctionalTest.php 1 0 tests/UnifiedSpecTests/EventCollector.php 2 0 tests/Operation/InsertOneFunctionalTest.php 1 0 tests/Database/FunctionalTestCase.php 1 0 tests/Model/ChangeStreamIteratorTest.php 1 0 tests/UnifiedSpecTests/UnifiedTestCase.php 2 0 tests/SpecTests/AtlasDataLakeSpecTest.php 2 0 tests/SpecTests/PrimaryStepDownSpecTest.php 1 0 tests/Operation/UpdateFunctionalTest.php 1 0 src/Model/ChangeStreamIterator.php 1 0 tests/UnifiedSpecTests/EventObserver.php 1 0 src/Operation/ListDatabaseNames.php 1 0 src/Operation/FindAndModify.php 2 0 tests/UnifiedSpecTests/RunOnRequirement.php 1 0 tests/UnifiedSpecTests/EntityMap.php 7 0 tests/TestCase.php 1 0 src/GridFS/CollectionWrapper.php 1 0 tests/SpecTests/FunctionalTestCase.php 2 0 tests/Operation/BulkWriteFunctionalTest.php 1 0 tests/Model/IndexInfoFunctionalTest.php 2 0 tests/UnifiedSpecTests/UnifiedSpecTest.php 3 0 src/Operation/Aggregate.php 3 0 tests/GridFS/WritableStreamFunctionalTest.php 1 0 tests/UnifiedSpecTests/UnifiedTestRunner.php 8 0 tests/Operation/MapReduceFunctionalTest.php 2 0 src/Client.php 3 0 tests/SpecTests/Context.php 3 0 src/Operation/EstimatedDocumentCount.php 2 0 tests/UnifiedSpecTests/Context.php 14 0 tests/SpecTests/TransactionsSpecTest.php 2 0 src/Database.php 1 0 tests/UnifiedSpecTests/DirtySessionObserver.php 1 0 tests/Collection/CrudSpecFunctionalTest.php 1 0 tests/Collection/FunctionalTestCase.php 2 0 tests/GridFS/ReadableStreamFunctionalTest.php 1 0 tests/UnifiedSpecTests/Operation.php 4 0 tests/UnifiedSpecTests/Constraint/Matches.php 3 0 tests/FunctionalTestCase.php 5 0 tests/UnifiedSpecTests/Loop.php 1 0 tests/UnifiedSpecTests/Constraint/IsBsonType.php 7 0 tests/SpecTests/ClientSideEncryptionSpecTest.php 1 0 tests/DocumentationExamplesTest.php 2 0 tests/Operation/WatchFunctionalTest.php 1 0 tests/PHPUnit/Functions.php 58 0 tests/GridFS/StreamWrapperFunctionalTest.php 1 0 ---------------------------------------------------------------------- A TOTAL OF 175 ERRORS WERE FIXED IN 52 FILES ---------------------------------------------------------------------- Time: 9.53 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.Namespaces.UseSpacing PHPCBF RESULT SUMMARY -------------------------------------------------------------------------- FILE FIXED REMAINING -------------------------------------------------------------------------- tests/Operation/DatabaseCommandFunctionalTest.php 1 0 src/Exception/BadMethodCallException.php 1 0 src/GridFS/Exception/FileNotFoundException.php 1 0 tests/Operation/ModifyCollectionFunctionalTest.php 1 0 src/Model/IndexInfoIteratorIterator.php 1 0 tests/Operation/DeleteTest.php 1 0 src/Exception/InvalidArgumentException.php 1 0 tests/CommandObserver.php 1 0 tests/Operation/CreateCollectionFunctionalTest.php 1 0 src/MapReduceResult.php 1 0 tests/GridFS/FunctionalTestCase.php 1 0 src/Operation/WithTransaction.php 1 0 src/Operation/ReplaceOne.php 1 0 src/Operation/FindOneAndDelete.php 1 0 src/Model/DatabaseInfo.php 1 0 src/Operation/DatabaseCommand.php 1 0 src/Operation/UpdateMany.php 1 0 tests/UnifiedSpecTests/CollectionData.php 1 0 src/Operation/UpdateOne.php 1 0 tests/Operation/ListDatabasesFunctionalTest.php 1 0 tests/Operation/CountFunctionalTest.php 1 0 tests/Operation/DropDatabaseFunctionalTest.php 1 0 src/Operation/DropDatabase.php 1 0 tests/Operation/ListDatabaseNamesFunctionalTest.php 1 0 tests/Operation/DropCollectionFunctionalTest.php 1 0 tests/Operation/ListCollectionsFunctionalTest.php 1 0 src/Model/CachingIterator.php 1 0 tests/GridFS/UnusableStream.php 1 0 tests/Operation/DeleteFunctionalTest.php 1 0 tests/UnifiedSpecTests/Util.php 1 0 tests/ClientFunctionalTest.php 1 0 src/Operation/CountDocuments.php 1 0 src/Operation/DropCollection.php 1 0 tests/Model/BSONArrayTest.php 1 0 tests/Database/CollectionManagementFunctionalTest.php 1 0 src/Model/CollectionInfo.php 1 0 src/Model/BSONDocument.php 1 0 src/Model/IndexInfo.php 1 0 tests/Operation/DistinctFunctionalTest.php 1 0 tests/UnifiedSpecTests/EventCollector.php 1 0 tests/Operation/InsertManyFunctionalTest.php 1 0 tests/Operation/InsertOneFunctionalTest.php 1 0 src/Operation/FindOne.php 1 0 tests/Model/BSONIteratorTest.php 1 0 src/Operation/Delete.php 1 0 tests/Model/ChangeStreamIteratorTest.php 1 0 tests/FunctionsTest.php 1 0 tests/SpecTests/CommandExpectations.php 1 0 tests/PedantryTest.php 2 0 tests/SpecTests/DocumentsMatchConstraintTest.php 2 0 src/Operation/ListIndexes.php 1 0 src/Model/IndexInput.php 1 0 tests/SpecTests/AtlasDataLakeSpecTest.php 1 0 tests/UnifiedSpecTests/UnifiedTestCase.php 1 0 src/Model/BSONIterator.php 1 0 tests/Operation/FindFunctionalTest.php 1 0 src/GridFS/WritableStream.php 1 0 tests/SpecTests/PrimaryStepDownSpecTest.php 1 0 tests/Model/BSONDocumentTest.php 1 0 src/Operation/FindOneAndUpdate.php 1 0 src/GridFS/StreamWrapper.php 2 0 tests/SpecTests/ChangeStreamsSpecTest.php 1 0 tests/Operation/UpdateFunctionalTest.php 1 0 tests/UnifiedSpecTests/EventObserver.php 1 0 tests/Operation/DropIndexesFunctionalTest.php 1 0 src/Operation/DropIndexes.php 1 0 src/Model/ChangeStreamIterator.php 1 0 src/GridFS/Exception/CorruptFileException.php 1 0 src/Operation/Count.php 1 0 src/Operation/Distinct.php 1 0 src/Model/BSONArray.php 1 0 tests/Operation/FindAndModifyFunctionalTest.php 1 0 src/functions.php 1 0 tests/Operation/ListCollectionNamesFunctionalTest.php 1 0 tests/UnifiedSpecTests/RunOnRequirement.php 1 0 src/Operation/FindAndModify.php 1 0 tests/SpecTests/ReadWriteConcernSpecTest.php 1 0 tests/TestCase.php 2 0 tests/SpecTests/RetryableReadsSpecTest.php 1 0 tests/UnifiedSpecTests/Constraint/MatchesTest.php 1 0 tests/UnifiedSpecTests/EntityMap.php 1 0 src/GridFS/Exception/StreamException.php 1 0 tests/Model/CachingIteratorTest.php 1 0 tests/Operation/CreateIndexesFunctionalTest.php 1 0 src/GridFS/CollectionWrapper.php 1 0 src/Operation/Update.php 1 0 tests/Model/IndexInfoFunctionalTest.php 1 0 src/Operation/CreateCollection.php 2 0 tests/Operation/BulkWriteFunctionalTest.php 1 0 tests/Operation/ListIndexesFunctionalTest.php 1 0 src/Operation/Aggregate.php 1 0 tests/UnifiedSpecTests/FailPointObserver.php 1 0 src/Operation/Find.php 2 0 src/Operation/CreateIndexes.php 1 0 tests/UnifiedSpecTests/UnifiedTestRunner.php 1 0 src/Client.php 1 0 tests/Operation/MapReduceFunctionalTest.php 1 0 src/Operation/InsertOne.php 1 0 src/Operation/InsertMany.php 1 0 tests/SpecTests/Context.php 1 0 tests/SpecTests/ResultExpectation.php 1 0 src/Operation/EstimatedDocumentCount.php 1 0 tests/UnifiedSpecTests/Context.php 2 0 src/Operation/FindOneAndReplace.php 1 0 src/Operation/Explain.php 1 0 tests/Database/DatabaseFunctionalTest.php 1 0 src/GridFS/ReadableStream.php 1 0 tests/SpecTests/FunctionalTestCase.php 1 0 tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php 2 0 tests/UnifiedSpecTests/ExpectedResult.php 1 0 tests/Operation/ExplainFunctionalTest.php 1 0 tests/Collection/CollectionFunctionalTest.php 1 0 src/Operation/ModifyCollection.php 1 0 tests/Operation/AggregateFunctionalTest.php 1 0 tests/SpecTests/TransactionsSpecTest.php 1 0 src/Database.php 1 0 tests/UnifiedSpecTests/Constraint/Matches.php 2 0 tests/UnifiedSpecTests/ExpectedError.php 1 0 tests/SpecTests/ErrorExpectation.php 1 0 src/Operation/Watch.php 1 0 src/Operation/MapReduce.php 2 0 tests/UnifiedSpecTests/UnifiedSpecTest.php 1 0 tests/UnifiedSpecTests/Operation.php 1 0 tests/UnifiedSpecTests/DirtySessionObserver.php 1 0 tests/SpecTests/RetryableWritesSpecTest.php 1 0 tests/FunctionalTestCase.php 2 0 src/Operation/BulkWrite.php 1 0 tests/GridFS/BucketFunctionalTest.php 2 0 src/ChangeStream.php 1 0 src/Operation/ListDatabaseNames.php 1 0 tests/UnifiedSpecTests/Constraint/IsBsonType.php 2 0 tests/UnifiedSpecTests/Loop.php 1 0 tests/GridFS/WritableStreamFunctionalTest.php 1 0 tests/SpecTests/DocumentsMatchConstraint.php 2 0 tests/Collection/CrudSpecFunctionalTest.php 1 0 tests/SpecTests/ClientSideEncryptionSpecTest.php 1 0 tests/SpecTests/Operation.php 1 0 tests/GridFS/ReadableStreamFunctionalTest.php 1 0 src/GridFS/Bucket.php 1 0 tests/SpecTests/CommandMonitoringSpecTest.php 1 0 tests/Operation/WatchFunctionalTest.php 1 0 tests/DocumentationExamplesTest.php 1 0 src/Collection.php 1 0 src/Command/ListCollections.php 1 0 src/Command/ListDatabases.php 1 0 tests/PHPUnit/Functions.php 1 0 tests/GridFS/StreamWrapperFunctionalTest.php 2 0 -------------------------------------------------------------------------- A TOTAL OF 162 ERRORS WERE FIXED IN 147 FILES -------------------------------------------------------------------------- Time: 11.55 secs; Memory: 10MB * phpcbf: fix PSR12.ControlStructures.ControlStructureSpacing PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- src/Operation/WithTransaction.php 3 0 src/Operation/DropCollection.php 2 0 src/Operation/FindOneAndUpdate.php 2 0 src/Operation/InsertOne.php 1 0 tests/UnifiedSpecTests/ExpectedResult.php 2 0 src/Operation/Update.php 2 0 src/Operation/FindAndModify.php 1 0 src/Operation/InsertMany.php 1 0 src/Operation/Aggregate.php 1 0 src/Operation/FindOneAndReplace.php 2 0 src/Operation/Find.php 2 0 src/Operation/Watch.php 4 0 tests/SpecTests/DocumentsMatchConstraint.php 2 0 src/Database.php 3 0 src/Operation/MapReduce.php 1 0 src/Operation/BulkWrite.php 1 0 src/Collection.php 3 0 ---------------------------------------------------------------------- A TOTAL OF 33 ERRORS WERE FIXED IN 17 FILES ---------------------------------------------------------------------- Time: 6.46 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- src/Model/ChangeStreamIterator.php 2 0 tests/SpecTests/ChangeStreamsSpecTest.php 3 0 tests/UnifiedSpecTests/EventObserver.php 3 0 tests/UnifiedSpecTests/Constraint/IsBsonType.php 21 0 tests/Collection/CrudSpecFunctionalTest.php 14 0 tests/UnifiedSpecTests/Operation.php 42 0 tests/SpecTests/DocumentsMatchConstraint.php 19 0 src/GridFS/Bucket.php 1 0 tests/SpecTests/Operation.php 79 0 tests/DocumentationExamplesTest.php 8 0 ---------------------------------------------------------------------- A TOTAL OF 192 ERRORS WERE FIXED IN 10 FILES ---------------------------------------------------------------------- Time: 5.07 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/ClientFunctionalTest.php 1 0 tests/PedantryTest.php 2 0 src/functions.php 1 0 tests/SpecTests/ResultExpectation.php 7 0 tests/UnifiedSpecTests/UnifiedSpecTest.php 1 0 src/Operation/Aggregate.php 1 0 tests/SpecTests/TransactionsSpecTest.php 1 0 src/Operation/Find.php 2 0 tests/SpecTests/ErrorExpectation.php 5 0 src/Operation/MapReduce.php 1 0 tests/FunctionalTestCase.php 8 0 tests/Collection/CrudSpecFunctionalTest.php 8 0 tests/UnifiedSpecTests/Operation.php 2 0 tests/SpecTests/Operation.php 4 0 tests/DocumentationExamplesTest.php 17 0 ---------------------------------------------------------------------- A TOTAL OF 61 ERRORS WERE FIXED IN 15 FILES ---------------------------------------------------------------------- Time: 5.32 secs; Memory: 10MB * phpcbf: fix PSR12.Operators.OperatorSpacing PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/FunctionalTestCase.php 2 0 tests/UnifiedSpecTests/Operation.php 1 0 ---------------------------------------------------------------------- A TOTAL OF 3 ERRORS WERE FIXED IN 2 FILES ---------------------------------------------------------------------- Time: 4.97 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.Arrays.SingleLineArrayWhitespace PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/Collection/CrudSpecFunctionalTest.php 3 0 tests/DocumentationExamplesTest.php 30 0 tests/UnifiedSpecTests/Operation.php 2 0 tests/SpecTests/Operation.php 3 0 tests/Operation/WatchFunctionalTest.php 3 0 ---------------------------------------------------------------------- A TOTAL OF 41 ERRORS WERE FIXED IN 5 FILES ---------------------------------------------------------------------- Time: 4.96 secs; Memory: 10MB * phpcbf: fix remaining fixable errors PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- src/Model/BSONIterator.php 2 0 src/GridFS/ReadableStream.php 1 0 tests/Operation/WatchFunctionalTest.php 1 0 tests/PHPUnit/Functions.php 1 0 ---------------------------------------------------------------------- A TOTAL OF 5 ERRORS WERE FIXED IN 4 FILES ---------------------------------------------------------------------- Time: 9.68 secs; Memory: 10MB * manual: fix Squiz.NamingConventions.ValidVariableName * phpcbf: use native type hints in tests PHPCBF RESULT SUMMARY -------------------------------------------------------------------------- FILE FIXED REMAINING -------------------------------------------------------------------------- tests/Operation/DatabaseCommandFunctionalTest.php 3 0 tests/Operation/DropDatabaseTest.php 1 0 tests/Operation/ExplainTest.php 1 0 tests/Operation/ModifyCollectionTest.php 2 0 tests/Operation/ModifyCollectionFunctionalTest.php 1 0 tests/CommandObserver.php 4 0 tests/Operation/DeleteTest.php 3 0 tests/Operation/CountDocumentsTest.php 2 0 tests/Operation/UpdateManyTest.php 4 0 tests/Operation/CountTest.php 2 0 tests/Model/DatabaseInfoTest.php 7 0 tests/Operation/CreateIndexesTest.php 4 0 tests/GridFS/FunctionalTestCase.php 3 0 tests/Operation/InsertManyTest.php 4 0 tests/Model/IndexInputTest.php 6 0 tests/Operation/FindAndModifyTest.php 2 0 tests/Operation/ListIndexesTest.php 1 0 tests/UnifiedSpecTests/CollectionData.php 2 0 tests/Operation/ListDatabasesFunctionalTest.php 10 0 tests/Operation/DropDatabaseFunctionalTest.php 10 0 tests/Operation/CreateCollectionFunctionalTest.php 6 0 tests/Operation/FindOneAndUpdateTest.php 5 0 tests/Operation/CountFunctionalTest.php 7 0 tests/Operation/DeleteFunctionalTest.php 8 0 tests/GridFS/UnusableStream.php 2 0 tests/ClientFunctionalTest.php 9 0 tests/UnifiedSpecTests/Util.php 1 0 tests/Database/CollectionManagementFunctionalTest.php 10 0 tests/Operation/UpdateOneTest.php 4 0 tests/Operation/DropIndexesTest.php 2 0 tests/Operation/ListCollectionsFunctionalTest.php 6 0 tests/Operation/FindTest.php 8 0 tests/Operation/DistinctTest.php 2 0 tests/Operation/ListDatabaseNamesFunctionalTest.php 10 0 tests/Operation/FindOneAndReplaceTest.php 5 0 tests/Operation/DropCollectionFunctionalTest.php 10 0 tests/UnifiedSpecTests/EventCollector.php 6 0 tests/Operation/InsertManyFunctionalTest.php 12 0 tests/Operation/MapReduceTest.php 2 0 tests/Model/BSONArrayTest.php 7 0 tests/Operation/InsertOneTest.php 2 0 tests/Operation/DropCollectionTest.php 1 0 tests/Operation/EstimatedDocumentCountTest.php 1 0 tests/FunctionsTest.php 8 0 tests/Model/IndexInfoTest.php 11 0 tests/SpecTests/DocumentsMatchConstraintTest.php 6 0 tests/PedantryTest.php 1 0 tests/SpecTests/CommandExpectations.php 6 0 tests/Operation/ReplaceOneTest.php 4 0 tests/Operation/InsertOneFunctionalTest.php 13 0 tests/Operation/WatchTest.php 3 0 tests/SpecTests/AtlasDataLakeSpecTest.php 10 0 tests/Operation/FindFunctionalTest.php 12 0 tests/Command/ListDatabasesTest.php 1 0 tests/SpecTests/PrimaryStepDownSpecTest.php 9 0 tests/Operation/UpdateTest.php 3 0 tests/Model/ChangeStreamIteratorTest.php 12 0 tests/Operation/DistinctFunctionalTest.php 7 0 tests/Operation/UpdateFunctionalTest.php 19 0 tests/Operation/DatabaseCommandTest.php 2 0 tests/SpecTests/ChangeStreamsSpecTest.php 14 0 tests/UnifiedSpecTests/EventObserver.php 10 0 tests/Command/ListCollectionsTest.php 1 0 tests/Model/BSONDocumentTest.php 8 0 tests/Operation/ListCollectionNamesFunctionalTest.php 4 0 tests/Operation/DropIndexesFunctionalTest.php 11 0 tests/SpecTests/ReadWriteConcernSpecTest.php 4 0 tests/Model/BSONIteratorTest.php 5 0 tests/Model/CollectionInfoTest.php 7 0 tests/UnifiedSpecTests/Constraint/MatchesTest.php 12 0 tests/UnifiedSpecTests/EntityMap.php 3 0 tests/TestCase.php 28 0 tests/SpecTests/RetryableReadsSpecTest.php 5 0 tests/Operation/CountDocumentsFunctionalTest.php 2 0 tests/Operation/AggregateTest.php 3 0 tests/Operation/CreateIndexesFunctionalTest.php 27 0 tests/Operation/BulkWriteFunctionalTest.php 22 0 tests/Model/CachingIteratorTest.php 12 0 tests/UnifiedSpecTests/FailPointObserver.php 6 0 tests/Operation/FindOneAndDeleteTest.php 2 0 tests/Model/IndexInfoFunctionalTest.php 3 0 tests/Operation/BulkWriteTest.php 36 0 tests/UnifiedSpecTests/UnifiedTestRunner.php 10 0 tests/Operation/MapReduceFunctionalTest.php 23 0 tests/SpecTests/ResultExpectation.php 3 0 tests/UnifiedSpecTests/Context.php 16 0 tests/Database/DatabaseFunctionalTest.php 18 0 tests/Operation/CreateCollectionTest.php 4 0 tests/SpecTests/FunctionalTestCase.php 18 0 tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php 10 0 tests/UnifiedSpecTests/ExpectedResult.php 1 0 tests/Collection/CollectionFunctionalTest.php 44 0 tests/Operation/AggregateFunctionalTest.php 32 0 tests/Operation/FindAndModifyFunctionalTest.php 18 0 tests/SpecTests/Context.php 8 0 tests/SpecTests/TransactionsSpecTest.php 9 0 tests/Operation/FindOneFunctionalTest.php 3 0 tests/Operation/ListIndexesFunctionalTest.php 5 0 tests/Operation/ExplainFunctionalTest.php 31 0 tests/UnifiedSpecTests/ExpectedError.php 2 0 tests/UnifiedSpecTests/Constraint/Matches.php 6 0 tests/UnifiedSpecTests/UnifiedSpecTest.php 8 0 tests/UnifiedSpecTests/Operation.php 2 0 tests/UnifiedSpecTests/DirtySessionObserver.php 5 0 tests/GridFS/BucketFunctionalTest.php 65 0 tests/SpecTests/ErrorExpectation.php 2 0 tests/UnifiedSpecTests/Loop.php 5 0 tests/SpecTests/RetryableWritesSpecTest.php 1 0 tests/GridFS/WritableStreamFunctionalTest.php 5 0 tests/SpecTests/DocumentsMatchConstraint.php 9 0 tests/FunctionalTestCase.php 16 0 tests/Collection/CrudSpecFunctionalTest.php 11 0 tests/SpecTests/ClientSideEncryptionSpecTest.php 35 0 tests/SpecTests/Operation.php 8 0 tests/ClientTest.php 13 0 tests/GridFS/ReadableStreamFunctionalTest.php 19 0 tests/SpecTests/CommandMonitoringSpecTest.php 6 0 tests/DocumentationExamplesTest.php 35 0 tests/Operation/WatchFunctionalTest.php 80 0 tests/PHPUnit/Functions.php 141 0 tests/GridFS/StreamWrapperFunctionalTest.php 13 0 -------------------------------------------------------------------------- A TOTAL OF 1290 ERRORS WERE FIXED IN 121 FILES -------------------------------------------------------------------------- Time: 23.19 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue Despite the method signatures changing, this change is acceptable as it does not create a BC break: https://3v4l.org/vN1M9 PHPCBF RESULT SUMMARY -------------------------------------------------------------------------- FILE FIXED REMAINING -------------------------------------------------------------------------- tests/ClientFunctionalTest.php 1 0 tests/Database/CollectionManagementFunctionalTest.php 1 0 tests/UnifiedSpecTests/UnifiedTestCase.php 3 0 tests/SpecTests/ReadWriteConcernSpecTest.php 3 0 tests/Model/BSONIteratorTest.php 1 0 tests/Operation/DropIndexesFunctionalTest.php 1 0 tests/SpecTests/AtlasDataLakeSpecTest.php 3 0 tests/UnifiedSpecTests/EntityMap.php 2 0 tests/SpecTests/PrimaryStepDownSpecTest.php 1 0 tests/SpecTests/ChangeStreamsSpecTest.php 4 0 tests/Operation/CreateIndexesFunctionalTest.php 1 0 tests/Operation/FindAndModifyFunctionalTest.php 1 0 tests/SpecTests/RetryableReadsSpecTest.php 1 0 tests/Operation/MapReduceFunctionalTest.php 2 0 tests/UnifiedSpecTests/UnifiedTestRunner.php 3 0 tests/SpecTests/ErrorExpectation.php 2 0 tests/Operation/AggregateFunctionalTest.php 2 0 tests/SpecTests/RetryableWritesSpecTest.php 1 0 tests/UnifiedSpecTests/Context.php 1 0 tests/UnifiedSpecTests/ExpectedResult.php 2 0 tests/UnifiedSpecTests/Constraint/Matches.php 1 0 tests/SpecTests/FunctionalTestCase.php 1 0 tests/FunctionalTestCase.php 6 0 tests/SpecTests/TransactionsSpecTest.php 3 0 tests/Collection/CrudSpecFunctionalTest.php 2 0 tests/UnifiedSpecTests/ExpectedError.php 2 0 tests/GridFS/BucketFunctionalTest.php 1 0 tests/SpecTests/ClientSideEncryptionSpecTest.php 5 0 tests/SpecTests/CommandMonitoringSpecTest.php 2 0 tests/PHPUnit/Functions.php 2 0 -------------------------------------------------------------------------- A TOTAL OF 61 ERRORS WERE FIXED IN 30 FILES -------------------------------------------------------------------------- Time: 19.24 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.PHP.ShortList PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/UnifiedSpecTests/CollectionData.php 1 0 src/Model/BSONIterator.php 1 0 tests/UnifiedSpecTests/FailPointObserver.php 1 0 tests/SpecTests/CommandExpectations.php 2 0 tests/SpecTests/AtlasDataLakeSpecTest.php 1 0 tests/SpecTests/ChangeStreamsSpecTest.php 1 0 tests/UnifiedSpecTests/EventObserver.php 1 0 src/GridFS/CollectionWrapper.php 2 0 tests/UnifiedSpecTests/Context.php 1 0 tests/SpecTests/FunctionalTestCase.php 1 0 tests/FunctionalTestCase.php 2 0 tests/Collection/CrudSpecFunctionalTest.php 1 0 ---------------------------------------------------------------------- A TOTAL OF 15 ERRORS WERE FIXED IN 12 FILES ---------------------------------------------------------------------- Time: 10.33 secs; Memory: 10MB * phpcbf: fix SlevomatCodingStandard.Classes.ClassConstantVisibility PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/UnifiedSpecTests/RunOnRequirement.php 5 0 src/Operation/FindOneAndUpdate.php 2 0 src/Operation/FindOneAndReplace.php 2 0 tests/SpecTests/PrimaryStepDownSpecTest.php 3 0 src/Operation/CreateCollection.php 2 0 tests/SpecTests/FunctionalTestCase.php 3 0 tests/SpecTests/ResultExpectation.php 13 0 tests/UnifiedSpecTests/UnifiedTestRunner.php 5 0 tests/SpecTests/TransactionsSpecTest.php 1 0 src/Operation/Find.php 3 0 src/ChangeStream.php 1 0 src/Operation/Explain.php 3 0 src/Operation/Watch.php 2 0 tests/UnifiedSpecTests/Operation.php 1 0 src/Operation/BulkWrite.php 6 0 tests/SpecTests/Operation.php 9 0 tests/SpecTests/ClientSideEncryptionSpecTest.php 1 0 tests/Operation/WatchFunctionalTest.php 2 0 ---------------------------------------------------------------------- A TOTAL OF 64 ERRORS WERE FIXED IN 18 FILES ---------------------------------------------------------------------- Time: 11.12 secs; Memory: 10MB * Sort php version specific sniffs to the top * phpcbf: fix SlevomatCodingStandard.Namespaces.NamespaceSpacing PHPCBF RESULT SUMMARY ---------------------------------------------------------------------- FILE FIXED REMAINING ---------------------------------------------------------------------- tests/PHPUnit/Functions.php 1 0 ---------------------------------------------------------------------- A TOTAL OF 1 ERROR WERE FIXED IN 1 FILE ---------------------------------------------------------------------- Time: 17.97 secs; Memory: 10MB * manual: fix SlevomatCodingStandard.TypeHints.*TypeHint.MissingAnyTypeHint * Remove obsolete configuration This is now enabled by default in doctrine/coding-standard * Clean up and document phpcs configuration file * Fix wrong method signature for inherited method * Remove wrong return type * manual: Use native typehints for internal functions * Make collectionName argument nullable Some tests don't have a collection name, which the previous documentation didn't cover for. --- .github/workflows/coding-standards.yml | 3 - .phpcs/autoload.php | 15 - CONTRIBUTING.md | 12 +- composer.json | 3 +- phpcs.xml.dist | 164 ++++++-- src/ChangeStream.php | 3 +- src/Client.php | 7 +- src/Collection.php | 10 +- src/Command/ListCollections.php | 1 + src/Command/ListDatabases.php | 1 + src/Database.php | 12 +- src/Exception/BadMethodCallException.php | 1 + src/Exception/InvalidArgumentException.php | 1 + src/GridFS/Bucket.php | 2 + src/GridFS/CollectionWrapper.php | 7 +- src/GridFS/Exception/CorruptFileException.php | 1 + .../Exception/FileNotFoundException.php | 1 + src/GridFS/Exception/StreamException.php | 7 +- src/GridFS/ReadableStream.php | 3 +- src/GridFS/StreamWrapper.php | 2 + src/GridFS/WritableStream.php | 4 + src/MapReduceResult.php | 1 + src/Model/BSONArray.php | 1 + src/Model/BSONDocument.php | 7 +- src/Model/BSONIterator.php | 7 +- src/Model/CachingIterator.php | 1 + src/Model/ChangeStreamIterator.php | 5 +- src/Model/CollectionInfo.php | 1 + src/Model/DatabaseInfo.php | 1 + src/Model/IndexInfo.php | 1 + src/Model/IndexInfoIteratorIterator.php | 1 + src/Model/IndexInput.php | 1 + src/Operation/Aggregate.php | 18 +- src/Operation/BulkWrite.php | 16 +- src/Operation/Count.php | 8 + src/Operation/CountDocuments.php | 1 + src/Operation/CreateCollection.php | 6 +- src/Operation/CreateIndexes.php | 1 + src/Operation/DatabaseCommand.php | 1 + src/Operation/Delete.php | 8 + src/Operation/DeleteMany.php | 7 + src/Operation/DeleteOne.php | 7 + src/Operation/Distinct.php | 8 + src/Operation/DropCollection.php | 7 +- src/Operation/DropDatabase.php | 1 + src/Operation/DropIndexes.php | 1 + src/Operation/EstimatedDocumentCount.php | 12 +- src/Operation/Explain.php | 19 +- src/Operation/Explainable.php | 6 + src/Operation/Find.php | 25 +- src/Operation/FindAndModify.php | 15 +- src/Operation/FindOne.php | 8 + src/Operation/FindOneAndDelete.php | 8 + src/Operation/FindOneAndReplace.php | 18 +- src/Operation/FindOneAndUpdate.php | 18 +- src/Operation/InsertMany.php | 4 +- src/Operation/InsertOne.php | 4 +- src/Operation/ListCollectionNames.php | 2 +- src/Operation/ListDatabaseNames.php | 3 +- src/Operation/ListIndexes.php | 1 + src/Operation/MapReduce.php | 6 +- src/Operation/ModifyCollection.php | 1 + src/Operation/ReplaceOne.php | 1 + src/Operation/Update.php | 14 +- src/Operation/UpdateMany.php | 8 + src/Operation/UpdateOne.php | 8 + src/Operation/Watch.php | 17 +- src/Operation/WithTransaction.php | 10 +- src/functions.php | 33 +- tests/ClientFunctionalTest.php | 18 +- tests/ClientTest.php | 26 +- tests/Collection/CollectionFunctionalTest.php | 87 ++-- tests/Collection/CrudSpecFunctionalTest.php | 45 +- tests/Collection/FunctionalTestCase.php | 4 +- tests/Command/ListCollectionsTest.php | 2 +- tests/Command/ListDatabasesTest.php | 2 +- tests/CommandObserver.php | 9 +- .../CollectionManagementFunctionalTest.php | 19 +- tests/Database/DatabaseFunctionalTest.php | 37 +- tests/Database/FunctionalTestCase.php | 2 +- tests/DocumentationExamplesTest.php | 128 +++--- tests/FunctionalTestCase.php | 69 +-- tests/FunctionsTest.php | 17 +- tests/GridFS/BucketFunctionalTest.php | 120 +++--- tests/GridFS/FunctionalTestCase.php | 7 +- tests/GridFS/ReadableStreamFunctionalTest.php | 41 +- tests/GridFS/StreamWrapperFunctionalTest.php | 30 +- tests/GridFS/UnusableStream.php | 5 +- tests/GridFS/WritableStreamFunctionalTest.php | 13 +- tests/Model/BSONArrayTest.php | 15 +- tests/Model/BSONDocumentTest.php | 17 +- tests/Model/BSONIteratorTest.php | 11 +- tests/Model/CachingIteratorTest.php | 25 +- tests/Model/ChangeStreamIteratorTest.php | 27 +- tests/Model/CollectionInfoTest.php | 14 +- tests/Model/DatabaseInfoTest.php | 14 +- tests/Model/IndexInfoFunctionalTest.php | 11 +- tests/Model/IndexInfoTest.php | 22 +- tests/Model/IndexInputTest.php | 12 +- tests/Operation/AggregateFunctionalTest.php | 63 +-- tests/Operation/AggregateTest.php | 6 +- tests/Operation/BulkWriteFunctionalTest.php | 45 +- tests/Operation/BulkWriteTest.php | 72 ++-- .../CountDocumentsFunctionalTest.php | 4 +- tests/Operation/CountDocumentsTest.php | 4 +- tests/Operation/CountFunctionalTest.php | 15 +- tests/Operation/CountTest.php | 4 +- .../CreateCollectionFunctionalTest.php | 13 +- tests/Operation/CreateCollectionTest.php | 8 +- .../Operation/CreateIndexesFunctionalTest.php | 51 +-- tests/Operation/CreateIndexesTest.php | 8 +- .../DatabaseCommandFunctionalTest.php | 7 +- tests/Operation/DatabaseCommandTest.php | 4 +- tests/Operation/DeleteFunctionalTest.php | 17 +- tests/Operation/DeleteTest.php | 7 +- tests/Operation/DistinctFunctionalTest.php | 15 +- tests/Operation/DistinctTest.php | 4 +- .../DropCollectionFunctionalTest.php | 19 +- tests/Operation/DropCollectionTest.php | 2 +- .../Operation/DropDatabaseFunctionalTest.php | 19 +- tests/Operation/DropDatabaseTest.php | 2 +- tests/Operation/DropIndexesFunctionalTest.php | 21 +- tests/Operation/DropIndexesTest.php | 4 +- .../Operation/EstimatedDocumentCountTest.php | 2 +- tests/Operation/ExplainFunctionalTest.php | 61 +-- tests/Operation/ExplainTest.php | 2 +- .../Operation/FindAndModifyFunctionalTest.php | 35 +- tests/Operation/FindAndModifyTest.php | 4 +- tests/Operation/FindFunctionalTest.php | 23 +- tests/Operation/FindOneAndDeleteTest.php | 4 +- tests/Operation/FindOneAndReplaceTest.php | 10 +- tests/Operation/FindOneAndUpdateTest.php | 10 +- tests/Operation/FindOneFunctionalTest.php | 4 +- tests/Operation/FindTest.php | 16 +- tests/Operation/FunctionalTestCase.php | 4 +- tests/Operation/InsertManyFunctionalTest.php | 27 +- tests/Operation/InsertManyTest.php | 8 +- tests/Operation/InsertOneFunctionalTest.php | 29 +- tests/Operation/InsertOneTest.php | 4 +- .../ListCollectionNamesFunctionalTest.php | 9 +- .../ListCollectionsFunctionalTest.php | 13 +- .../ListDatabaseNamesFunctionalTest.php | 21 +- .../Operation/ListDatabasesFunctionalTest.php | 21 +- tests/Operation/ListIndexesFunctionalTest.php | 11 +- tests/Operation/ListIndexesTest.php | 2 +- tests/Operation/MapReduceFunctionalTest.php | 49 +-- tests/Operation/MapReduceTest.php | 4 +- .../ModifyCollectionFunctionalTest.php | 3 +- tests/Operation/ModifyCollectionTest.php | 4 +- tests/Operation/ReplaceOneTest.php | 8 +- tests/Operation/UpdateFunctionalTest.php | 39 +- tests/Operation/UpdateManyTest.php | 8 +- tests/Operation/UpdateOneTest.php | 8 +- tests/Operation/UpdateTest.php | 6 +- tests/Operation/WatchFunctionalTest.php | 176 ++++---- tests/Operation/WatchTest.php | 6 +- tests/PHPUnit/Functions.php | 395 +++++++++--------- tests/PedantryTest.php | 6 +- tests/SpecTests/AtlasDataLakeSpecTest.php | 25 +- tests/SpecTests/ChangeStreamsSpecTest.php | 22 +- .../ClientSideEncryptionSpecTest.php | 73 ++-- tests/SpecTests/CommandExpectations.php | 23 +- tests/SpecTests/CommandMonitoringSpecTest.php | 14 +- tests/SpecTests/Context.php | 32 +- tests/SpecTests/DocumentsMatchConstraint.php | 35 +- .../DocumentsMatchConstraintTest.php | 14 +- tests/SpecTests/ErrorExpectation.php | 10 +- tests/SpecTests/FunctionalTestCase.php | 39 +- tests/SpecTests/Operation.php | 114 ++++- tests/SpecTests/PrimaryStepDownSpecTest.php | 29 +- tests/SpecTests/ReadWriteConcernSpecTest.php | 7 +- tests/SpecTests/ResultExpectation.php | 40 +- tests/SpecTests/RetryableReadsSpecTest.php | 7 +- tests/SpecTests/RetryableWritesSpecTest.php | 3 +- tests/SpecTests/TransactionsSpecTest.php | 24 +- tests/TestCase.php | 42 +- tests/UnifiedSpecTests/CollectionData.php | 7 +- .../Constraint/IsBsonType.php | 37 +- .../Constraint/IsBsonTypeTest.php | 22 +- tests/UnifiedSpecTests/Constraint/Matches.php | 25 +- .../Constraint/MatchesTest.php | 25 +- tests/UnifiedSpecTests/Context.php | 64 +-- .../UnifiedSpecTests/DirtySessionObserver.php | 13 +- tests/UnifiedSpecTests/EntityMap.php | 25 +- tests/UnifiedSpecTests/EventCollector.php | 17 +- tests/UnifiedSpecTests/EventObserver.php | 28 +- tests/UnifiedSpecTests/ExpectedError.php | 7 +- tests/UnifiedSpecTests/ExpectedResult.php | 11 +- tests/UnifiedSpecTests/FailPointObserver.php | 15 +- tests/UnifiedSpecTests/Loop.php | 13 +- tests/UnifiedSpecTests/Operation.php | 66 ++- tests/UnifiedSpecTests/RunOnRequirement.php | 23 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 24 +- tests/UnifiedSpecTests/UnifiedTestCase.php | 7 +- tests/UnifiedSpecTests/UnifiedTestRunner.php | 50 ++- tests/UnifiedSpecTests/Util.php | 11 +- 196 files changed, 2303 insertions(+), 1653 deletions(-) delete mode 100644 .phpcs/autoload.php diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 7ba3c8a21..b9f2fc134 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -60,9 +60,6 @@ jobs: key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - - name: "Require doctrine/coding-standard" - run: "composer require --no-update doctrine/coding-standard=^6.0" - - name: "Install dependencies with Composer" run: "composer install --no-interaction --no-progress --no-suggest" diff --git a/.phpcs/autoload.php b/.phpcs/autoload.php deleted file mode 100644 index 45e90ad16..000000000 --- a/.phpcs/autoload.php +++ /dev/null @@ -1,15 +0,0 @@ - - - - - + + + + - + - .phpcs/autoload.php - - .phpcs src tests + + + + - - - - + - - + + - - + + - + + + + - - - + + + + + + + + + + - - - + + + - @@ -55,25 +62,29 @@ - + + + + - - + + + + - - - - - - + + + + + @@ -88,30 +99,91 @@ - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + tests + + + tests + + + tests + + + + + + + + src + + + src + + + src + + + + + + /src/GridFS/StreamWrapper /tests/DocumentationExamplesTest.php /tests/GridFS/UnusableStream.php - /tests/PHPUnit/ConstraintTrait.php diff --git a/src/ChangeStream.php b/src/ChangeStream.php index ea0de63e4..627dae304 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -24,6 +24,7 @@ use MongoDB\Driver\Exception\ServerException; use MongoDB\Exception\ResumeTokenException; use MongoDB\Model\ChangeStreamIterator; + use function call_user_func; use function in_array; @@ -40,7 +41,7 @@ class ChangeStream implements Iterator * @deprecated 1.4 * @todo Remove this in 2.0 (see: PHPLIB-360) */ - const CURSOR_NOT_FOUND = 43; + public const CURSOR_NOT_FOUND = 43; /** @var int */ private static $cursorNotFound = 43; diff --git a/src/Client.php b/src/Client.php index f3215d349..10aea4f4d 100644 --- a/src/Client.php +++ b/src/Client.php @@ -38,6 +38,7 @@ use MongoDB\Operation\ListDatabases; use MongoDB\Operation\Watch; use Throwable; + use function is_array; use function is_string; @@ -283,7 +284,7 @@ public function getWriteConcern() * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function listDatabaseNames(array $options = []) : Iterator + public function listDatabaseNames(array $options = []): Iterator { $operation = new ListDatabaseNames($options); $server = select_server($this->manager, $options); @@ -384,7 +385,7 @@ public function watch(array $pipeline = [], array $options = []) return $operation->execute($server); } - private static function getVersion() : string + private static function getVersion(): string { if (self::$version === null) { try { @@ -397,7 +398,7 @@ private static function getVersion() : string return self::$version; } - private function mergeDriverInfo(array $driver) : array + private function mergeDriverInfo(array $driver): array { $mergedDriver = [ 'name' => 'PHPLIB', diff --git a/src/Collection.php b/src/Collection.php index a449c7edc..85a1a4ecf 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -58,6 +58,7 @@ use MongoDB\Operation\UpdateOne; use MongoDB\Operation\Watch; use Traversable; + use function array_diff_key; use function array_intersect_key; use function current; @@ -234,7 +235,8 @@ public function aggregate(array $pipeline, array $options = []) * * A read concern is also not compatible with transactions. */ - if (! isset($options['readConcern']) && + if ( + ! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options) && ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage)) @@ -246,10 +248,12 @@ public function aggregate(array $pipeline, array $options = []) $options['typeMap'] = $this->typeMap; } - if ($hasWriteStage && + if ( + $hasWriteStage && ! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && - ! is_in_transaction($options)) { + ! is_in_transaction($options) + ) { $options['writeConcern'] = $this->writeConcern; } diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index 4f85f1371..4302e4f09 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -24,6 +24,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Model\CachingIterator; use MongoDB\Operation\Executable; + use function is_array; use function is_bool; use function is_integer; diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index c9fa58fc8..0a18d4961 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -24,6 +24,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Operation\Executable; + use function current; use function is_array; use function is_bool; diff --git a/src/Database.php b/src/Database.php index fadc64be5..5d2901280 100644 --- a/src/Database.php +++ b/src/Database.php @@ -41,6 +41,7 @@ use MongoDB\Operation\ModifyCollection; use MongoDB\Operation\Watch; use Traversable; + use function is_array; use function strlen; @@ -215,7 +216,8 @@ public function aggregate(array $pipeline, array $options = []) * * A read concern is also not compatible with transactions. */ - if (! isset($options['readConcern']) && + if ( + ! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options) && ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage)) @@ -227,10 +229,12 @@ public function aggregate(array $pipeline, array $options = []) $options['typeMap'] = $this->typeMap; } - if ($hasWriteStage && + if ( + $hasWriteStage && ! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && - ! is_in_transaction($options)) { + ! is_in_transaction($options) + ) { $options['writeConcern'] = $this->writeConcern; } @@ -413,7 +417,7 @@ public function getWriteConcern() * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function listCollectionNames(array $options = []) : Iterator + public function listCollectionNames(array $options = []): Iterator { $operation = new ListCollectionNames($this->databaseName, $options); $server = select_server($this->manager, $options); diff --git a/src/Exception/BadMethodCallException.php b/src/Exception/BadMethodCallException.php index 00cd79cf2..34227536a 100644 --- a/src/Exception/BadMethodCallException.php +++ b/src/Exception/BadMethodCallException.php @@ -18,6 +18,7 @@ namespace MongoDB\Exception; use BadMethodCallException as BaseBadMethodCallException; + use function sprintf; class BadMethodCallException extends BaseBadMethodCallException implements Exception diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 83271c180..8e93d5faa 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -18,6 +18,7 @@ namespace MongoDB\Exception; use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException; + use function array_pop; use function count; use function get_debug_type; diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php index ac9630515..a0fe14149 100644 --- a/src/GridFS/Bucket.php +++ b/src/GridFS/Bucket.php @@ -33,6 +33,7 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\Find; use stdClass; + use function array_intersect_key; use function fopen; use function get_resource_type; @@ -629,6 +630,7 @@ public function uploadFromStream($filename, $source, array $options = []) if (@stream_copy_to_stream($source, $destination) === false) { $destinationUri = $this->createPathForFile($this->getRawFileDocumentForStream($destination)); + throw StreamException::uploadFailed($filename, $source, $destinationUri); } diff --git a/src/GridFS/CollectionWrapper.php b/src/GridFS/CollectionWrapper.php index 0b7f43091..106134bef 100644 --- a/src/GridFS/CollectionWrapper.php +++ b/src/GridFS/CollectionWrapper.php @@ -26,6 +26,7 @@ use MongoDB\UpdateResult; use MultipleIterator; use stdClass; + use function abs; use function count; use function is_numeric; @@ -342,7 +343,7 @@ private function ensureIndexes() $this->ensureChunksIndex(); } - private function indexKeysMatch(array $expectedKeys, array $actualKeys) : bool + private function indexKeysMatch(array $expectedKeys, array $actualKeys): bool { if (count($expectedKeys) !== count($actualKeys)) { return false; @@ -353,8 +354,8 @@ private function indexKeysMatch(array $expectedKeys, array $actualKeys) : bool $iterator->attachIterator(new ArrayIterator($actualKeys)); foreach ($iterator as $key => $value) { - list($expectedKey, $actualKey) = $key; - list($expectedValue, $actualValue) = $value; + [$expectedKey, $actualKey] = $key; + [$expectedValue, $actualValue] = $value; if ($expectedKey !== $actualKey) { return false; diff --git a/src/GridFS/Exception/CorruptFileException.php b/src/GridFS/Exception/CorruptFileException.php index c35372569..7a4506d33 100644 --- a/src/GridFS/Exception/CorruptFileException.php +++ b/src/GridFS/Exception/CorruptFileException.php @@ -18,6 +18,7 @@ namespace MongoDB\GridFS\Exception; use MongoDB\Exception\RuntimeException; + use function sprintf; class CorruptFileException extends RuntimeException diff --git a/src/GridFS/Exception/FileNotFoundException.php b/src/GridFS/Exception/FileNotFoundException.php index f0d222381..79dc7432a 100644 --- a/src/GridFS/Exception/FileNotFoundException.php +++ b/src/GridFS/Exception/FileNotFoundException.php @@ -18,6 +18,7 @@ namespace MongoDB\GridFS\Exception; use MongoDB\Exception\RuntimeException; + use function MongoDB\BSON\fromPHP; use function MongoDB\BSON\toJSON; use function sprintf; diff --git a/src/GridFS/Exception/StreamException.php b/src/GridFS/Exception/StreamException.php index 53aa9e351..241f1b9a4 100644 --- a/src/GridFS/Exception/StreamException.php +++ b/src/GridFS/Exception/StreamException.php @@ -3,6 +3,7 @@ namespace MongoDB\GridFS\Exception; use MongoDB\Exception\RuntimeException; + use function MongoDB\BSON\fromPHP; use function MongoDB\BSON\toJSON; use function sprintf; @@ -14,7 +15,7 @@ class StreamException extends RuntimeException * @param resource $source * @param resource $destination */ - public static function downloadFromFilenameFailed(string $filename, $source, $destination) : self + public static function downloadFromFilenameFailed(string $filename, $source, $destination): self { $sourceMetadata = stream_get_meta_data($source); $destinationMetadata = stream_get_meta_data($destination); @@ -27,7 +28,7 @@ public static function downloadFromFilenameFailed(string $filename, $source, $de * @param resource $source * @param resource $destination */ - public static function downloadFromIdFailed($id, $source, $destination) : self + public static function downloadFromIdFailed($id, $source, $destination): self { $idString = toJSON(fromPHP(['_id' => $id])); $sourceMetadata = stream_get_meta_data($source); @@ -37,7 +38,7 @@ public static function downloadFromIdFailed($id, $source, $destination) : self } /** @param resource $source */ - public static function uploadFailed(string $filename, $source, string $destinationUri) : self + public static function uploadFailed(string $filename, $source, string $destinationUri): self { $sourceMetadata = stream_get_meta_data($source); diff --git a/src/GridFS/ReadableStream.php b/src/GridFS/ReadableStream.php index c49474eb1..d577375f8 100644 --- a/src/GridFS/ReadableStream.php +++ b/src/GridFS/ReadableStream.php @@ -21,6 +21,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\Exception\CorruptFileException; use stdClass; + use function ceil; use function floor; use function is_integer; @@ -95,7 +96,7 @@ public function __construct(CollectionWrapper $collectionWrapper, stdClass $file if ($this->length > 0) { $this->numChunks = (integer) ceil($this->length / $this->chunkSize); - $this->expectedLastChunkSize = ($this->length - (($this->numChunks - 1) * $this->chunkSize)); + $this->expectedLastChunkSize = $this->length - (($this->numChunks - 1) * $this->chunkSize); } } diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index a5136b349..dd316741b 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -20,6 +20,7 @@ use MongoDB\BSON\UTCDateTime; use stdClass; use Throwable; + use function explode; use function get_class; use function in_array; @@ -30,6 +31,7 @@ use function stream_wrapper_register; use function stream_wrapper_unregister; use function trigger_error; + use const E_USER_WARNING; use const SEEK_CUR; use const SEEK_END; diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php index 2e12285dd..706de40ec 100644 --- a/src/GridFS/WritableStream.php +++ b/src/GridFS/WritableStream.php @@ -23,6 +23,7 @@ use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Exception\InvalidArgumentException; use stdClass; + use function array_intersect_key; use function hash_final; use function hash_init; @@ -261,6 +262,9 @@ private function abort() $this->isClosed = true; } + /** + * @return mixed + */ private function fileCollectionInsert() { $this->file['length'] = $this->length; diff --git a/src/MapReduceResult.php b/src/MapReduceResult.php index aaa36b172..e4e862293 100644 --- a/src/MapReduceResult.php +++ b/src/MapReduceResult.php @@ -20,6 +20,7 @@ use IteratorAggregate; use stdClass; use Traversable; + use function call_user_func; /** diff --git a/src/Model/BSONArray.php b/src/Model/BSONArray.php index 8230a5e5a..bdcb240b4 100644 --- a/src/Model/BSONArray.php +++ b/src/Model/BSONArray.php @@ -21,6 +21,7 @@ use JsonSerializable; use MongoDB\BSON\Serializable; use MongoDB\BSON\Unserializable; + use function array_values; use function MongoDB\recursive_copy; diff --git a/src/Model/BSONDocument.php b/src/Model/BSONDocument.php index b00ac4894..f6381d5cf 100644 --- a/src/Model/BSONDocument.php +++ b/src/Model/BSONDocument.php @@ -21,6 +21,7 @@ use JsonSerializable; use MongoDB\BSON\Serializable; use MongoDB\BSON\Unserializable; + use function MongoDB\recursive_copy; /** @@ -50,11 +51,11 @@ public function __clone() * @see http://php.net/arrayobject.construct * @param array $input * @param integer $flags - * @param string $iterator_class + * @param string $iteratorClass */ - public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $iterator_class = 'ArrayIterator') + public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $iteratorClass = 'ArrayIterator') { - parent::__construct($input, $flags, $iterator_class); + parent::__construct($input, $flags, $iteratorClass); } /** diff --git a/src/Model/BSONIterator.php b/src/Model/BSONIterator.php index 093bfbe55..761984efa 100644 --- a/src/Model/BSONIterator.php +++ b/src/Model/BSONIterator.php @@ -20,6 +20,7 @@ use Iterator; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; + use function is_array; use function MongoDB\BSON\toPHP; use function sprintf; @@ -137,13 +138,13 @@ private function advance() return; } - if (($this->bufferLength - $this->position) < self::$bsonSize) { + if ($this->bufferLength - $this->position < self::$bsonSize) { throw new UnexpectedValueException(sprintf('Expected at least %d bytes; %d remaining', self::$bsonSize, $this->bufferLength - $this->position)); } - list(,$documentLength) = unpack('V', substr($this->buffer, $this->position, self::$bsonSize)); + [, $documentLength] = unpack('V', substr($this->buffer, $this->position, self::$bsonSize)); - if (($this->bufferLength - $this->position) < $documentLength) { + if ($this->bufferLength - $this->position < $documentLength) { throw new UnexpectedValueException(sprintf('Expected %d bytes; %d remaining', $documentLength, $this->bufferLength - $this->position)); } diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index b904ecae3..9898aefab 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -21,6 +21,7 @@ use Iterator; use IteratorIterator; use Traversable; + use function count; use function current; use function key; diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index 6f0a1a89d..76952c789 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -28,6 +28,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\ResumeTokenException; use MongoDB\Exception\UnexpectedValueException; + use function count; use function is_array; use function is_integer; @@ -160,7 +161,7 @@ public function getResumeToken() /** * Returns the server the cursor is running on. */ - public function getServer() : Server + public function getServer(): Server { return $this->server; } @@ -248,11 +249,13 @@ private function extractResumeToken($document) if (! isset($resumeToken)) { $this->isValid = false; + throw ResumeTokenException::notFound(); } if (! is_array($resumeToken) && ! is_object($resumeToken)) { $this->isValid = false; + throw ResumeTokenException::invalidType($resumeToken); } diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php index f4d61df2b..afbf63527 100644 --- a/src/Model/CollectionInfo.php +++ b/src/Model/CollectionInfo.php @@ -19,6 +19,7 @@ use ArrayAccess; use MongoDB\Exception\BadMethodCallException; + use function array_key_exists; /** diff --git a/src/Model/DatabaseInfo.php b/src/Model/DatabaseInfo.php index 385b46497..40e377fc0 100644 --- a/src/Model/DatabaseInfo.php +++ b/src/Model/DatabaseInfo.php @@ -19,6 +19,7 @@ use ArrayAccess; use MongoDB\Exception\BadMethodCallException; + use function array_key_exists; /** diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php index ee8a29357..dcce520c2 100644 --- a/src/Model/IndexInfo.php +++ b/src/Model/IndexInfo.php @@ -19,6 +19,7 @@ use ArrayAccess; use MongoDB\Exception\BadMethodCallException; + use function array_key_exists; use function array_search; diff --git a/src/Model/IndexInfoIteratorIterator.php b/src/Model/IndexInfoIteratorIterator.php index c02cf1be1..6434ba56c 100644 --- a/src/Model/IndexInfoIteratorIterator.php +++ b/src/Model/IndexInfoIteratorIterator.php @@ -19,6 +19,7 @@ use IteratorIterator; use Traversable; + use function array_key_exists; /** diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php index d7ec50fc2..bf44fb5d8 100644 --- a/src/Model/IndexInput.php +++ b/src/Model/IndexInput.php @@ -19,6 +19,7 @@ use MongoDB\BSON\Serializable; use MongoDB\Exception\InvalidArgumentException; + use function is_array; use function is_float; use function is_int; diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 0a9e77791..96afe4c4a 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -30,6 +30,7 @@ use MongoDB\Exception\UnsupportedException; use stdClass; use Traversable; + use function current; use function is_array; use function is_bool; @@ -291,6 +292,7 @@ public function execute(Server $server) if (isset($this->options['readConcern'])) { throw UnsupportedException::readConcernNotSupportedInTransaction(); } + if (isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); } @@ -330,12 +332,19 @@ public function execute(Server $server) return new ArrayIterator($result->result); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->createCommandDocument($server, $this->hasWriteStage()); } - private function createCommandDocument(Server $server, bool $hasWriteStage) : array + private function createCommandDocument(Server $server, bool $hasWriteStage): array { $cmd = [ 'aggregate' => $this->collectionName ?? 1, @@ -344,7 +353,8 @@ private function createCommandDocument(Server $server, bool $hasWriteStage) : ar $cmd['allowDiskUse'] = $this->options['allowDiskUse']; - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; @@ -378,7 +388,7 @@ private function createCommandDocument(Server $server, bool $hasWriteStage) : ar return $cmd; } - private function createCommandOptions() : array + private function createCommandOptions(): array { $cmdOptions = []; @@ -421,7 +431,7 @@ private function createOptions($hasWriteStage, $hasExplain) return $options; } - private function hasWriteStage() : bool + private function hasWriteStage(): bool { return is_last_pipeline_operator_write($this->pipeline); } diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index 95bd4bb1c..4168e560a 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -25,6 +25,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function array_key_exists; use function count; use function current; @@ -45,12 +46,12 @@ */ class BulkWrite implements Executable { - const DELETE_MANY = 'deleteMany'; - const DELETE_ONE = 'deleteOne'; - const INSERT_ONE = 'insertOne'; - const REPLACE_ONE = 'replaceOne'; - const UPDATE_MANY = 'updateMany'; - const UPDATE_ONE = 'updateOne'; + public const DELETE_MANY = 'deleteMany'; + public const DELETE_ONE = 'deleteOne'; + public const INSERT_ONE = 'insertOne'; + public const REPLACE_ONE = 'replaceOne'; + public const UPDATE_MANY = 'updateMany'; + public const UPDATE_ONE = 'updateOne'; /** @var integer */ private static $wireVersionForArrayFilters = 6; @@ -356,7 +357,8 @@ public function execute(Server $server) $options = ['ordered' => $this->options['ordered']]; - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 2e00ae555..e2624b1f8 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -26,6 +26,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function is_float; @@ -184,6 +185,13 @@ public function execute(Server $server) return (integer) $result->n; } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->createCommandDocument(); diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index 77499e5b7..541d2f7bd 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -22,6 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; + use function array_intersect_key; use function count; use function current; diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index 08d547add..c10502316 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -24,6 +24,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function is_bool; @@ -32,6 +33,7 @@ use function is_string; use function MongoDB\server_supports_feature; use function trigger_error; + use const E_USER_DEPRECATED; /** @@ -43,8 +45,8 @@ */ class CreateCollection implements Executable { - const USE_POWER_OF_2_SIZES = 1; - const NO_PADDING = 2; + public const USE_POWER_OF_2_SIZES = 1; + public const NO_PADDING = 2; /** @var integer */ private static $wireVersionForCollation = 5; diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php index ba53d95b7..3075a38a8 100644 --- a/src/Operation/CreateIndexes.php +++ b/src/Operation/CreateIndexes.php @@ -25,6 +25,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\Model\IndexInput; + use function array_map; use function is_array; use function is_integer; diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php index af0f76248..749004e86 100644 --- a/src/Operation/DatabaseCommand.php +++ b/src/Operation/DatabaseCommand.php @@ -23,6 +23,7 @@ use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\Exception\InvalidArgumentException; + use function is_array; use function is_object; diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 65cc6f6e9..43122c5ef 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -25,6 +25,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function is_array; use function is_object; use function is_string; @@ -165,6 +166,13 @@ public function execute(Server $server) return new DeleteResult($writeResult); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { $cmd = ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]]; diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index ffda516ca..7a25957c9 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -83,6 +83,13 @@ public function execute(Server $server) return $this->delete->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->delete->getCommandDocument($server); diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index 742a58f73..4c2136bfe 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -83,6 +83,13 @@ public function execute(Server $server) return $this->delete->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->delete->getCommandDocument($server); diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index f8e169ca7..d48d05426 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -26,6 +26,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function is_integer; @@ -177,6 +178,13 @@ public function execute(Server $server) return $result->values; } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->createCommandDocument(); diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 10f16e1ed..8b1e6bd2a 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -24,6 +24,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function MongoDB\server_supports_feature; @@ -129,8 +130,10 @@ public function execute(Server $server) /* The server may return an error if the collection does not exist. * Check for an error code (or message for pre-3.2 servers) and * return the command reply instead of throwing. */ - if ($e->getCode() === self::$errorCodeNamespaceNotFound || - $e->getMessage() === self::$errorMessageNamespaceNotFound) { + if ( + $e->getCode() === self::$errorCodeNamespaceNotFound || + $e->getMessage() === self::$errorMessageNamespaceNotFound + ) { return $e->getResultDocument(); } diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php index 5a4335a7d..d5ba860d7 100644 --- a/src/Operation/DropDatabase.php +++ b/src/Operation/DropDatabase.php @@ -24,6 +24,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function MongoDB\server_supports_feature; diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php index 322e3b10f..6c6bae2ab 100644 --- a/src/Operation/DropIndexes.php +++ b/src/Operation/DropIndexes.php @@ -24,6 +24,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function is_integer; diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index dd9bcb4bf..f67b010a6 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -26,6 +26,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; + use function array_intersect_key; use function is_integer; use function MongoDB\server_supports_feature; @@ -136,12 +137,19 @@ public function execute(Server $server) return $command->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->createCommand($server)->getCommandDocument($server); } - private function createAggregate() : Aggregate + private function createAggregate(): Aggregate { return new Aggregate( $this->databaseName, @@ -162,7 +170,7 @@ private function createCommand(Server $server) : $this->createCount(); } - private function createCount() : Count + private function createCount(): Count { return new Count($this->databaseName, $this->collectionName, [], $this->options); } diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php index aa240bb51..ab93f5e5e 100644 --- a/src/Operation/Explain.php +++ b/src/Operation/Explain.php @@ -18,11 +18,13 @@ namespace MongoDB\Operation; use MongoDB\Driver\Command; +use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function is_string; @@ -37,9 +39,9 @@ */ class Explain implements Executable { - const VERBOSITY_ALL_PLANS = 'allPlansExecution'; - const VERBOSITY_EXEC_STATS = 'executionStats'; - const VERBOSITY_QUERY = 'queryPlanner'; + public const VERBOSITY_ALL_PLANS = 'allPlansExecution'; + public const VERBOSITY_EXEC_STATS = 'executionStats'; + public const VERBOSITY_QUERY = 'queryPlanner'; /** @var integer */ private static $wireVersionForAggregate = 7; @@ -101,6 +103,15 @@ public function __construct($databaseName, Explainable $explainable, array $opti $this->options = $options; } + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object + * @throws UnsupportedException if the server does not support explaining the operation + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ public function execute(Server $server) { if ($this->explainable instanceof Distinct && ! server_supports_feature($server, self::$wireVersionForDistinct)) { @@ -151,7 +162,7 @@ private function createOptions() return $options; } - private function isFindAndModify($explainable) + private function isFindAndModify(Explainable $explainable): bool { if ($explainable instanceof FindAndModify || $explainable instanceof FindOneAndDelete || $explainable instanceof FindOneAndReplace || $explainable instanceof FindOneAndUpdate) { return true; diff --git a/src/Operation/Explainable.php b/src/Operation/Explainable.php index fb531f239..51810e41e 100644 --- a/src/Operation/Explainable.php +++ b/src/Operation/Explainable.php @@ -27,5 +27,11 @@ */ interface Explainable extends Executable { + /** + * Returns the command document for this operation. + * + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server); } diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 4555ebd5d..a3d8f188d 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -26,6 +26,7 @@ use MongoDB\Driver\Session; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function is_array; use function is_bool; use function is_integer; @@ -33,6 +34,7 @@ use function is_string; use function MongoDB\server_supports_feature; use function trigger_error; + use const E_USER_DEPRECATED; /** @@ -45,9 +47,9 @@ */ class Find implements Executable, Explainable { - const NON_TAILABLE = 1; - const TAILABLE = 2; - const TAILABLE_AWAIT = 3; + public const NON_TAILABLE = 1; + public const TAILABLE = 2; + public const TAILABLE_AWAIT = 3; /** @var integer */ private static $wireVersionForCollation = 5; @@ -201,9 +203,11 @@ public function __construct($databaseName, $collectionName, $filter, array $opti throw InvalidArgumentException::invalidType('"cursorType" option', $options['cursorType'], 'integer'); } - if ($options['cursorType'] !== self::NON_TAILABLE && + if ( + $options['cursorType'] !== self::NON_TAILABLE && $options['cursorType'] !== self::TAILABLE && - $options['cursorType'] !== self::TAILABLE_AWAIT) { + $options['cursorType'] !== self::TAILABLE_AWAIT + ) { throw new InvalidArgumentException('Invalid value for "cursorType" option: ' . $options['cursorType']); } } @@ -343,6 +347,13 @@ public function execute(Server $server) return $cursor; } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->createCommandDocument(); @@ -351,7 +362,7 @@ public function getCommandDocument(Server $server) /** * Construct a command document for Find */ - private function createCommandDocument() + private function createCommandDocument(): array { $cmd = ['find' => $this->collectionName, 'filter' => (object) $this->filter]; @@ -383,6 +394,7 @@ private function createCommandDocument() $options[$modifier[0]] = $options['modifiers'][$modifier[1]]; } } + unset($options['modifiers']); return $cmd + $options; @@ -425,6 +437,7 @@ private function createQueryOptions() if ($this->options['cursorType'] === self::TAILABLE) { $options['tailable'] = true; } + if ($this->options['cursorType'] === self::TAILABLE_AWAIT) { $options['tailable'] = true; $options['awaitData'] = true; diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 9e1e5949d..48b70da76 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -25,6 +25,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function is_bool; @@ -272,6 +273,13 @@ public function execute(Server $server) return $result->value ?? null; } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->createCommandDocument($server); @@ -312,7 +320,8 @@ private function createCommandDocument(Server $server) } } - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; @@ -342,7 +351,7 @@ private function createOptions() return $options; } - private function isAcknowledgedWriteConcern() : bool + private function isAcknowledgedWriteConcern(): bool { if (! isset($this->options['writeConcern'])) { return true; @@ -351,7 +360,7 @@ private function isAcknowledgedWriteConcern() : bool return $this->options['writeConcern']->getW() > 1 || $this->options['writeConcern']->getJournal(); } - private function isHintSupported(Server $server) : bool + private function isHintSupported(Server $server): bool { $requiredWireVersion = $this->isAcknowledgedWriteConcern() ? self::$wireVersionForHintServerSideError : self::$wireVersionForHint; diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index 48f601ce6..3319c90df 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -21,6 +21,7 @@ use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; /** @@ -131,6 +132,13 @@ public function execute(Server $server) return $document === false ? null : $document; } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->find->getCommandDocument($server); diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 88ed57f7e..c55485f42 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -21,6 +21,7 @@ use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function is_array; use function is_object; @@ -116,6 +117,13 @@ public function execute(Server $server) return $this->findAndModify->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->findAndModify->getCommandDocument($server); diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 61256f518..19851729f 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -21,6 +21,7 @@ use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function is_array; use function is_integer; use function is_object; @@ -35,8 +36,8 @@ */ class FindOneAndReplace implements Executable, Explainable { - const RETURN_DOCUMENT_BEFORE = 1; - const RETURN_DOCUMENT_AFTER = 2; + public const RETURN_DOCUMENT_BEFORE = 1; + public const RETURN_DOCUMENT_AFTER = 2; /** @var FindAndModify */ private $findAndModify; @@ -127,8 +128,10 @@ public function __construct($databaseName, $collectionName, $filter, $replacemen throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer'); } - if ($options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && - $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE) { + if ( + $options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && + $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE + ) { throw new InvalidArgumentException('Invalid value for "returnDocument" option: ' . $options['returnDocument']); } @@ -161,6 +164,13 @@ public function execute(Server $server) return $this->findAndModify->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->findAndModify->getCommandDocument($server); diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index c8121a9b5..e5840b86d 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -21,6 +21,7 @@ use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function is_array; use function is_integer; use function is_object; @@ -36,8 +37,8 @@ */ class FindOneAndUpdate implements Executable, Explainable { - const RETURN_DOCUMENT_BEFORE = 1; - const RETURN_DOCUMENT_AFTER = 2; + public const RETURN_DOCUMENT_BEFORE = 1; + public const RETURN_DOCUMENT_AFTER = 2; /** @var FindAndModify */ private $findAndModify; @@ -131,8 +132,10 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer'); } - if ($options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && - $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE) { + if ( + $options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && + $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE + ) { throw new InvalidArgumentException('Invalid value for "returnDocument" option: ' . $options['returnDocument']); } @@ -165,6 +168,13 @@ public function execute(Server $server) return $this->findAndModify->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->findAndModify->getCommandDocument($server); diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index 768907592..cca60ccac 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -25,6 +25,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\InsertManyResult; + use function is_array; use function is_bool; use function is_object; @@ -147,7 +148,8 @@ public function execute(Server $server) $options = ['ordered' => $this->options['ordered']]; - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index 84d6a4aa1..91f3222bc 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -25,6 +25,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\InsertOneResult; + use function is_array; use function is_bool; use function is_object; @@ -122,7 +123,8 @@ public function execute(Server $server) throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index e36bf5688..4c7c03b34 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -67,7 +67,7 @@ public function __construct($databaseName, array $options = []) * @return Iterator * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function execute(Server $server) : Iterator + public function execute(Server $server): Iterator { return new CallbackIterator( $this->listCollections->execute($server), diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php index a9d5a8a87..531be3403 100644 --- a/src/Operation/ListDatabaseNames.php +++ b/src/Operation/ListDatabaseNames.php @@ -24,6 +24,7 @@ use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; + use function array_column; /** @@ -76,7 +77,7 @@ public function __construct(array $options = []) * @throws UnexpectedValueException if the command response was malformed * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function execute(Server $server) : Iterator + public function execute(Server $server): Iterator { $result = $this->listDatabases->execute($server); diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index 9702e34d3..61d9fa754 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -27,6 +27,7 @@ use MongoDB\Model\CachingIterator; use MongoDB\Model\IndexInfoIterator; use MongoDB\Model\IndexInfoIteratorIterator; + use function is_integer; /** diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index c1bf6926a..a16a389eb 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -31,6 +31,7 @@ use MongoDB\Exception\UnsupportedException; use MongoDB\MapReduceResult; use stdClass; + use function current; use function is_array; use function is_bool; @@ -41,6 +42,7 @@ use function MongoDB\is_mapreduce_output_inline; use function MongoDB\server_supports_feature; use function trigger_error; + use const E_USER_DEPRECATED; /** @@ -305,6 +307,7 @@ public function execute(Server $server) if (isset($this->options['readConcern'])) { throw UnsupportedException::readConcernNotSupportedInTransaction(); } + if (isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); } @@ -384,7 +387,8 @@ private function createCommand(Server $server) } } - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php index 3b5177fd5..9c3d34140 100644 --- a/src/Operation/ModifyCollection.php +++ b/src/Operation/ModifyCollection.php @@ -24,6 +24,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; + use function current; use function is_array; use function MongoDB\server_supports_feature; diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index e55bf74af..551a6fa47 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -22,6 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\UpdateResult; + use function is_array; use function is_object; use function MongoDB\is_first_key_operator; diff --git a/src/Operation/Update.php b/src/Operation/Update.php index b3b86e0c6..2f71c57b6 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -25,6 +25,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\UpdateResult; + use function is_array; use function is_bool; use function is_object; @@ -216,7 +217,8 @@ public function execute(Server $server) $bulkOptions = []; - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; @@ -230,6 +232,13 @@ public function execute(Server $server) return new UpdateResult($writeResult); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { $cmd = ['update' => $this->collectionName, 'updates' => [['q' => $this->filter, 'u' => $this->update] + $this->createUpdateOptions()]]; @@ -238,7 +247,8 @@ public function getCommandDocument(Server $server) $cmd['writeConcern'] = $this->options['writeConcern']; } - if (! empty($this->options['bypassDocumentValidation']) && + if ( + ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) ) { $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index eb1bd6cd5..48aa509ca 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -22,6 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\UpdateResult; + use function is_array; use function is_object; use function MongoDB\is_first_key_operator; @@ -117,6 +118,13 @@ public function execute(Server $server) return $this->update->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->update->getCommandDocument($server); diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index e8e7ef842..337e969b6 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -22,6 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; use MongoDB\UpdateResult; + use function is_array; use function is_object; use function MongoDB\is_first_key_operator; @@ -117,6 +118,13 @@ public function execute(Server $server) return $this->update->execute($server); } + /** + * Returns the command document for this operation. + * + * @see Explainable::getCommandDocument() + * @param Server $server + * @return array + */ public function getCommandDocument(Server $server) { return $this->update->getCommandDocument($server); diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 1c88b87be..56813970c 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -32,6 +32,7 @@ use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; use MongoDB\Model\ChangeStreamIterator; + use function array_intersect_key; use function array_unshift; use function count; @@ -55,8 +56,8 @@ */ class Watch implements Executable, /* @internal */ CommandSubscriber { - const FULL_DOCUMENT_DEFAULT = 'default'; - const FULL_DOCUMENT_UPDATE_LOOKUP = 'updateLookup'; + public const FULL_DOCUMENT_DEFAULT = 'default'; + public const FULL_DOCUMENT_UPDATE_LOOKUP = 'updateLookup'; /** @var integer */ private static $wireVersionForStartAtOperationTime = 7; @@ -264,8 +265,10 @@ final public function commandSucceeded(CommandSucceededEvent $event) $this->postBatchResumeToken = $reply->cursor->postBatchResumeToken; } - if ($this->shouldCaptureOperationTime($event->getServer()) && - isset($reply->operationTime) && $reply->operationTime instanceof TimestampInterface) { + if ( + $this->shouldCaptureOperationTime($event->getServer()) && + isset($reply->operationTime) && $reply->operationTime instanceof TimestampInterface + ) { $this->operationTime = $reply->operationTime; } } @@ -419,9 +422,11 @@ private function shouldCaptureOperationTime(Server $server) return false; } - if (isset($this->changeStreamOptions['resumeAfter']) || + if ( + isset($this->changeStreamOptions['resumeAfter']) || isset($this->changeStreamOptions['startAfter']) || - isset($this->changeStreamOptions['startAtOperationTime'])) { + isset($this->changeStreamOptions['startAtOperationTime']) + ) { return false; } diff --git a/src/Operation/WithTransaction.php b/src/Operation/WithTransaction.php index 3d0474e7e..6278972dd 100644 --- a/src/Operation/WithTransaction.php +++ b/src/Operation/WithTransaction.php @@ -6,6 +6,7 @@ use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\Session; use Throwable; + use function call_user_func; use function time; @@ -69,7 +70,8 @@ public function execute(Session $session) $session->abortTransaction(); } - if ($e instanceof RuntimeException && + if ( + $e instanceof RuntimeException && $e->hasErrorLabel('TransientTransactionError') && ! $this->isTransactionTimeLimitExceeded($startTime) ) { @@ -88,7 +90,8 @@ public function execute(Session $session) try { $session->commitTransaction(); } catch (RuntimeException $e) { - if ($e->getCode() !== 50 /* MaxTimeMSExpired */ && + if ( + $e->getCode() !== 50 /* MaxTimeMSExpired */ && $e->hasErrorLabel('UnknownTransactionCommitResult') && ! $this->isTransactionTimeLimitExceeded($startTime) ) { @@ -96,7 +99,8 @@ public function execute(Session $session) continue; } - if ($e->hasErrorLabel('TransientTransactionError') && + if ( + $e->hasErrorLabel('TransientTransactionError') && ! $this->isTransactionTimeLimitExceeded($startTime) ) { // Restart the transaction, invoking the callback again diff --git a/src/functions.php b/src/functions.php index e828e669a..30bacf011 100644 --- a/src/functions.php +++ b/src/functions.php @@ -28,6 +28,7 @@ use MongoDB\Operation\WithTransaction; use ReflectionClass; use ReflectionException; + use function end; use function get_object_vars; use function in_array; @@ -71,7 +72,7 @@ function apply_type_map_to_document($document, array $typeMap) * @return string * @throws InvalidArgumentException */ -function generate_index_name($document) +function generate_index_name($document): string { if ($document instanceof Serializable) { $document = $document->bsonSerialize(); @@ -104,7 +105,7 @@ function generate_index_name($document) * @return boolean * @throws InvalidArgumentException */ -function is_first_key_operator($document) +function is_first_key_operator($document): bool { if ($document instanceof Serializable) { $document = $document->bsonSerialize(); @@ -131,7 +132,7 @@ function is_first_key_operator($document) * @param mixed $pipeline * @return boolean */ -function is_pipeline($pipeline) +function is_pipeline($pipeline): bool { if (! is_array($pipeline)) { return false; @@ -172,7 +173,7 @@ function is_pipeline($pipeline) * @param array $options Command options * @return boolean */ -function is_in_transaction(array $options) +function is_in_transaction(array $options): bool { if (isset($options['session']) && $options['session'] instanceof Session && $options['session']->isInTransaction()) { return true; @@ -191,7 +192,7 @@ function is_in_transaction(array $options) * @param array $pipeline List of pipeline operations * @return boolean */ -function is_last_pipeline_operator_write(array $pipeline) +function is_last_pipeline_operator_write(array $pipeline): bool { $lastOp = end($pipeline); @@ -215,7 +216,7 @@ function is_last_pipeline_operator_write(array $pipeline) * @return boolean * @throws InvalidArgumentException */ -function is_mapreduce_output_inline($out) +function is_mapreduce_output_inline($out): bool { if (! is_array($out) && ! is_object($out)) { return false; @@ -246,7 +247,7 @@ function is_mapreduce_output_inline($out) * @param integer $feature Feature constant (i.e. wire protocol version) * @return boolean */ -function server_supports_feature(Server $server, $feature) +function server_supports_feature(Server $server, int $feature): bool { $info = $server->getInfo(); $maxWireVersion = isset($info['maxWireVersion']) ? (integer) $info['maxWireVersion'] : 0; @@ -255,11 +256,19 @@ function server_supports_feature(Server $server, $feature) return $minWireVersion <= $feature && $maxWireVersion >= $feature; } -function is_string_array($input) +/** + * Return whether the input is an array of strings. + * + * @internal + * @param mixed $input + * @return boolean + */ +function is_string_array($input): bool { if (! is_array($input)) { return false; } + foreach ($input as $item) { if (! is_string($item)) { return false; @@ -315,7 +324,7 @@ function recursive_copy($element) * @param string $fieldPath The field path to apply the root type to * @return array */ -function create_field_path_type_map(array $typeMap, $fieldPath) +function create_field_path_type_map(array $typeMap, string $fieldPath): array { // If some field paths already exist, we prefix them with the field path we are assuming as the new root if (isset($typeMap['fieldPaths']) && is_array($typeMap['fieldPaths'])) { @@ -383,7 +392,7 @@ function with_transaction(Session $session, callable $callback, array $transacti * @param array $options * @return Session|null */ -function extract_session_from_options(array $options) +function extract_session_from_options(array $options): ?Session { if (! isset($options['session']) || ! $options['session'] instanceof Session) { return null; @@ -399,7 +408,7 @@ function extract_session_from_options(array $options) * @param array $options * @return ReadPreference|null */ -function extract_read_preference_from_options(array $options) +function extract_read_preference_from_options(array $options): ?ReadPreference { if (! isset($options['readPreference']) || ! $options['readPreference'] instanceof ReadPreference) { return null; @@ -415,7 +424,7 @@ function extract_read_preference_from_options(array $options) * @internal * @return Server */ -function select_server(Manager $manager, array $options) +function select_server(Manager $manager, array $options): Server { $session = extract_session_from_options($options); if ($session instanceof Session && $session->getServer() !== null) { diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index 0e9a29235..213b5922a 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -8,6 +8,7 @@ use MongoDB\Driver\Session; use MongoDB\Model\DatabaseInfo; use MongoDB\Model\DatabaseInfoIterator; + use function call_user_func; use function is_callable; use function sprintf; @@ -21,7 +22,7 @@ class ClientFunctionalTest extends FunctionalTestCase /** @var Client */ private $client; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -29,12 +30,12 @@ public function setUp() : void $this->client->dropDatabase($this->getDatabaseName()); } - public function testGetManager() + public function testGetManager(): void { $this->assertInstanceOf(Manager::class, $this->client->getManager()); } - public function testDropDatabase() + public function testDropDatabase(): void { $bulkWrite = new BulkWrite(); $bulkWrite->insert(['x' => 1]); @@ -47,7 +48,7 @@ public function testDropDatabase() $this->assertCollectionCount($this->getNamespace(), 0); } - public function testListDatabases() + public function testListDatabases(): void { $bulkWrite = new BulkWrite(); $bulkWrite->insert(['x' => 1]); @@ -63,13 +64,13 @@ public function testListDatabases() $this->assertInstanceOf(DatabaseInfo::class, $database); } - $this->assertDatabaseExists($this->getDatabaseName(), function (DatabaseInfo $info) { + $this->assertDatabaseExists($this->getDatabaseName(), function (DatabaseInfo $info): void { $this->assertFalse($info->isEmpty()); $this->assertGreaterThan(0, $info->getSizeOnDisk()); }); } - public function testListDatabaseNames() + public function testListDatabaseNames(): void { $bulkWrite = new BulkWrite(); $bulkWrite->insert(['x' => 1]); @@ -95,7 +96,7 @@ public function testListDatabaseNames() * @param string $databaseName * @param callable $callback */ - private function assertDatabaseExists($databaseName, $callback = null) + private function assertDatabaseExists(string $databaseName, ?callable $callback = null): void { if ($callback !== null && ! is_callable($callback)) { throw new InvalidArgumentException('$callback is not a callable'); @@ -119,11 +120,12 @@ private function assertDatabaseExists($databaseName, $callback = null) } } - public function testStartSession() + public function testStartSession(): void { if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { $this->markTestSkipped('startSession() is only supported on FCV 3.6 or higher'); } + $this->assertInstanceOf(Session::class, $this->client->startSession()); } } diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 55d3a13a5..192868e75 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -15,7 +15,7 @@ */ class ClientTest extends TestCase { - public function testConstructorDefaultUri() + public function testConstructorDefaultUri(): void { $client = new Client(); @@ -25,7 +25,7 @@ public function testConstructorDefaultUri() /** * @doesNotPerformAssertions */ - public function testConstructorAutoEncryptionOpts() + public function testConstructorAutoEncryptionOpts(): void { $autoEncryptionOpts = [ 'keyVaultClient' => new Client(static::getUri()), @@ -39,7 +39,7 @@ public function testConstructorAutoEncryptionOpts() /** * @dataProvider provideInvalidConstructorDriverOptions */ - public function testConstructorDriverOptionTypeChecks(array $driverOptions, string $exception = InvalidArgumentException::class) + public function testConstructorDriverOptionTypeChecks(array $driverOptions, string $exception = InvalidArgumentException::class): void { $this->expectException($exception); new Client(static::getUri(), [], $driverOptions); @@ -73,14 +73,14 @@ public function provideInvalidConstructorDriverOptions() return $options; } - public function testToString() + public function testToString(): void { $client = new Client(static::getUri()); $this->assertSame(static::getUri(), (string) $client); } - public function testSelectCollectionInheritsOptions() + public function testSelectCollectionInheritsOptions(): void { $uriOptions = [ 'readConcernLevel' => ReadConcern::LOCAL, @@ -106,7 +106,7 @@ public function testSelectCollectionInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectCollectionPassesOptions() + public function testSelectCollectionPassesOptions(): void { $collectionOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -129,7 +129,7 @@ public function testSelectCollectionPassesOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testGetSelectsDatabaseAndInheritsOptions() + public function testGetSelectsDatabaseAndInheritsOptions(): void { $uriOptions = ['w' => WriteConcern::MAJORITY]; @@ -142,7 +142,7 @@ public function testGetSelectsDatabaseAndInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectDatabaseInheritsOptions() + public function testSelectDatabaseInheritsOptions(): void { $uriOptions = [ 'readConcernLevel' => ReadConcern::LOCAL, @@ -168,7 +168,7 @@ public function testSelectDatabaseInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectDatabasePassesOptions() + public function testSelectDatabasePassesOptions(): void { $databaseOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -191,7 +191,7 @@ public function testSelectDatabasePassesOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testCreateClientEncryption() + public function testCreateClientEncryption(): void { $client = new Client(static::getUri()); @@ -204,7 +204,7 @@ public function testCreateClientEncryption() $this->assertInstanceOf(ClientEncryption::class, $clientEncryption); } - public function testCreateClientEncryptionWithKeyVaultClient() + public function testCreateClientEncryptionWithKeyVaultClient(): void { $client = new Client(static::getUri()); @@ -218,7 +218,7 @@ public function testCreateClientEncryptionWithKeyVaultClient() $this->assertInstanceOf(ClientEncryption::class, $clientEncryption); } - public function testCreateClientEncryptionWithManager() + public function testCreateClientEncryptionWithManager(): void { $client = new Client(static::getUri()); @@ -232,7 +232,7 @@ public function testCreateClientEncryptionWithManager() $this->assertInstanceOf(ClientEncryption::class, $clientEncryption); } - public function testCreateClientEncryptionWithInvalidKeyVaultClient() + public function testCreateClientEncryptionWithInvalidKeyVaultClient(): void { $client = new Client(static::getUri()); diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index ba231e8dd..1c6a995ac 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -14,6 +14,7 @@ use MongoDB\MapReduceResult; use MongoDB\Operation\Count; use MongoDB\Tests\CommandObserver; + use function array_filter; use function call_user_func; use function is_scalar; @@ -30,7 +31,7 @@ class CollectionFunctionalTest extends FunctionalTestCase /** * @dataProvider provideInvalidDatabaseAndCollectionNames */ - public function testConstructorDatabaseNameArgument($databaseName) + public function testConstructorDatabaseNameArgument($databaseName): void { $this->expectException(InvalidArgumentException::class); // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) @@ -40,7 +41,7 @@ public function testConstructorDatabaseNameArgument($databaseName) /** * @dataProvider provideInvalidDatabaseAndCollectionNames */ - public function testConstructorCollectionNameArgument($collectionName) + public function testConstructorCollectionNameArgument($collectionName): void { $this->expectException(InvalidArgumentException::class); // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) @@ -58,7 +59,7 @@ public function provideInvalidDatabaseAndCollectionNames() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $options); @@ -87,32 +88,32 @@ public function provideInvalidConstructorOptions() return $options; } - public function testGetManager() + public function testGetManager(): void { $this->assertSame($this->manager, $this->collection->getManager()); } - public function testToString() + public function testToString(): void { $this->assertEquals($this->getNamespace(), (string) $this->collection); } - public function getGetCollectionName() + public function getGetCollectionName(): void { $this->assertEquals($this->getCollectionName(), $this->collection->getCollectionName()); } - public function getGetDatabaseName() + public function getGetDatabaseName(): void { $this->assertEquals($this->getDatabaseName(), $this->collection->getDatabaseName()); } - public function testGetNamespace() + public function testGetNamespace(): void { $this->assertEquals($this->getNamespace(), $this->collection->getNamespace()); } - public function testAggregateWithinTransaction() + public function testAggregateWithinTransaction(): void { $this->skipIfTransactionsAreNotSupported(); @@ -143,14 +144,14 @@ public function testAggregateWithinTransaction() } } - public function testCreateIndexSplitsCommandOptions() + public function testCreateIndexSplitsCommandOptions(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $this->collection->createIndex( ['x' => 1], [ @@ -162,7 +163,7 @@ function () { ] ); }, - function (array $event) { + function (array $event): void { $command = $event['started']->getCommand(); $this->assertObjectHasAttribute('lsid', $command); $this->assertObjectHasAttribute('maxTimeMS', $command); @@ -176,7 +177,7 @@ function (array $event) { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testDistinctWithTypeMap(array $typeMap, array $expectedDocuments) + public function testDistinctWithTypeMap(array $typeMap, array $expectedDocuments): void { $bulkWrite = new BulkWrite(['ordered' => true]); $bulkWrite->insert([ @@ -255,7 +256,7 @@ public function provideTypeMapOptionsAndExpectedDocuments() ]; } - public function testDrop() + public function testDrop(): void { $writeResult = $this->collection->insertOne(['x' => 1]); $this->assertEquals(1, $writeResult->getInsertedCount()); @@ -268,13 +269,13 @@ public function testDrop() /** * @todo Move this to a unit test once Manager can be mocked */ - public function testDropIndexShouldNotAllowWildcardCharacter() + public function testDropIndexShouldNotAllowWildcardCharacter(): void { $this->expectException(InvalidArgumentException::class); $this->collection->dropIndex('*'); } - public function testExplain() + public function testExplain(): void { $this->createFixtures(3); @@ -285,7 +286,7 @@ public function testExplain() $this->assertArrayHasKey('queryPlanner', $result); } - public function testFindOne() + public function testFindOne(): void { $this->createFixtures(5); @@ -300,7 +301,7 @@ public function testFindOne() $this->assertSameDocument($expected, $this->collection->findOne($filter, $options)); } - public function testFindWithinTransaction() + public function testFindWithinTransaction(): void { $this->skipIfTransactionsAreNotSupported(); @@ -331,7 +332,7 @@ public function testFindWithinTransaction() } } - public function testWithOptionsInheritsOptions() + public function testWithOptionsInheritsOptions(): void { $collectionOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -357,7 +358,7 @@ public function testWithOptionsInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testWithOptionsPassesOptions() + public function testWithOptionsPassesOptions(): void { $collectionOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -385,7 +386,7 @@ public function testWithOptionsPassesOptions() * @group matrix-testing-exclude-server-5.0-driver-4.0 * @group matrix-testing-exclude-server-5.0-driver-4.2 */ - public function testMapReduce() + public function testMapReduce(): void { $this->createFixtures(3); @@ -412,7 +413,7 @@ public function collectionMethodClosures() { return [ [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->aggregate( [['$match' => ['_id' => ['$lt' => 3]]]], ['session' => $session] + $options @@ -421,7 +422,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->bulkWrite( [['insertOne' => [['test' => 'foo']]]], ['session' => $session] + $options @@ -441,7 +442,7 @@ function($collection, $session, $options = []) { */ [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->countDocuments( [], ['session' => $session] + $options @@ -461,7 +462,7 @@ function($collection, $session, $options = []) { */ [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->deleteMany( ['test' => 'foo'], ['session' => $session] + $options @@ -470,7 +471,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->deleteOne( ['test' => 'foo'], ['session' => $session] + $options @@ -479,7 +480,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->distinct( '_id', [], @@ -529,7 +530,7 @@ function($collection, $session, $options = []) { */ [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->find( ['test' => 'foo'], ['session' => $session] + $options @@ -538,7 +539,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->findOne( ['test' => 'foo'], ['session' => $session] + $options @@ -547,7 +548,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->findOneAndDelete( ['test' => 'foo'], ['session' => $session] + $options @@ -556,7 +557,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->findOneAndReplace( ['test' => 'foo'], [], @@ -566,7 +567,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->findOneAndUpdate( ['test' => 'foo'], ['$set' => ['updated' => 1]], @@ -576,7 +577,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->insertMany( [ ['test' => 'foo'], @@ -588,7 +589,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->insertOne( ['test' => 'foo'], ['session' => $session] + $options @@ -620,7 +621,7 @@ function($collection, $session, $options = []) { */ [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->replaceOne( ['test' => 'foo'], [], @@ -630,7 +631,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->updateMany( ['test' => 'foo'], ['$set' => ['updated' => 1]], @@ -640,7 +641,7 @@ function ($collection, $session, $options = []) { ], [ - function ($collection, $session, $options = []) { + function ($collection, $session, $options = []): void { $collection->updateOne( ['test' => 'foo'], ['$set' => ['updated' => 1]], @@ -689,7 +690,7 @@ function ($rw) { /** * @dataProvider collectionMethodClosures */ - public function testMethodDoesNotInheritReadWriteConcernInTranasaction(Closure $method) + public function testMethodDoesNotInheritReadWriteConcernInTranasaction(Closure $method): void { $this->skipIfTransactionsAreNotSupported(); @@ -704,10 +705,10 @@ public function testMethodDoesNotInheritReadWriteConcernInTranasaction(Closure $ ]); (new CommandObserver())->observe( - function () use ($method, $collection, $session) { + function () use ($method, $collection, $session): void { call_user_func($method, $collection, $session); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } @@ -717,7 +718,7 @@ function (array $event) { /** * @dataProvider collectionWriteMethodClosures */ - public function testMethodInTransactionWithWriteConcernOption($method) + public function testMethodInTransactionWithWriteConcernOption($method): void { $this->skipIfTransactionsAreNotSupported(); @@ -739,7 +740,7 @@ public function testMethodInTransactionWithWriteConcernOption($method) /** * @dataProvider collectionReadMethodClosures */ - public function testMethodInTransactionWithReadConcernOption($method) + public function testMethodInTransactionWithReadConcernOption($method): void { $this->skipIfTransactionsAreNotSupported(); @@ -764,7 +765,7 @@ public function testMethodInTransactionWithReadConcernOption($method) * @param integer $n * @param array $executeBulkWriteOptions */ - private function createFixtures($n, array $executeBulkWriteOptions = []) + private function createFixtures(int $n, array $executeBulkWriteOptions = []): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index 6cfd608ec..398b6a4aa 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -14,6 +14,7 @@ use MongoDB\UpdateResult; use MultipleIterator; use PHPUnit_Framework_SkippedTestError; + use function array_diff_key; use function array_key_exists; use function array_map; @@ -38,7 +39,7 @@ class CrudSpecFunctionalTest extends FunctionalTestCase /** @var Collection */ private $expectedCollection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -49,7 +50,7 @@ public function setUp() : void /** * @dataProvider provideSpecificationTests */ - public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion) + public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion): void { if (isset($minServerVersion) || isset($maxServerVersion)) { $this->checkServerVersion($minServerVersion, $maxServerVersion); @@ -100,14 +101,14 @@ public function provideSpecificationTests() * @param Collection $expectedCollection * @param Collection $actualCollection */ - private function assertEquivalentCollections($expectedCollection, $actualCollection) + private function assertEquivalentCollections(Collection $expectedCollection, Collection $actualCollection): void { $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); $mi->attachIterator($expectedCollection->find()); $mi->attachIterator($actualCollection->find()); foreach ($mi as $documents) { - list($expectedDocument, $actualDocument) = $documents; + [$expectedDocument, $actualDocument] = $documents; $this->assertSameDocument($expectedDocument, $actualDocument); } } @@ -119,7 +120,7 @@ private function assertEquivalentCollections($expectedCollection, $actualCollect * @param string|null $maxServerVersion * @throws PHPUnit_Framework_SkippedTestError */ - private function checkServerVersion($minServerVersion, $maxServerVersion) + private function checkServerVersion(?string $minServerVersion, ?string $maxServerVersion): void { $serverVersion = $this->getServerVersion(); @@ -147,11 +148,13 @@ private function executeOperation(array $operation) $operation['arguments']['pipeline'], array_diff_key($operation['arguments'], ['pipeline' => 1]) ); + case 'bulkWrite': return $this->collection->bulkWrite( array_map([$this, 'prepareBulkWriteRequest'], $operation['arguments']['requests']), $operation['arguments']['options'] ?? [] ); + case 'count': case 'countDocuments': case 'find': @@ -159,8 +162,10 @@ private function executeOperation(array $operation) $operation['arguments']['filter'] ?? [], array_diff_key($operation['arguments'], ['filter' => 1]) ); + case 'estimatedDocumentCount': return $this->collection->estimatedDocumentCount($operation['arguments']); + case 'deleteMany': case 'deleteOne': case 'findOneAndDelete': @@ -168,12 +173,14 @@ private function executeOperation(array $operation) $operation['arguments']['filter'], array_diff_key($operation['arguments'], ['filter' => 1]) ); + case 'distinct': return $this->collection->distinct( $operation['arguments']['fieldName'], $operation['arguments']['filter'] ?? [], array_diff_key($operation['arguments'], ['fieldName' => 1, 'filter' => 1]) ); + case 'findOneAndReplace': $operation['arguments'] = $this->prepareFindAndModifyArguments($operation['arguments']); // Fall through @@ -184,6 +191,7 @@ private function executeOperation(array $operation) $operation['arguments']['replacement'], array_diff_key($operation['arguments'], ['filter' => 1, 'replacement' => 1]) ); + case 'findOneAndUpdate': $operation['arguments'] = $this->prepareFindAndModifyArguments($operation['arguments']); // Fall through @@ -195,16 +203,19 @@ private function executeOperation(array $operation) $operation['arguments']['update'], array_diff_key($operation['arguments'], ['filter' => 1, 'update' => 1]) ); + case 'insertMany': return $this->collection->insertMany( $operation['arguments']['documents'], $operation['arguments']['options'] ?? [] ); + case 'insertOne': return $this->collection->insertOne( $operation['arguments']['document'], array_diff_key($operation['arguments'], ['document' => 1]) ); + default: throw new LogicException('Unsupported operation: ' . $operation['name']); } @@ -220,7 +231,7 @@ private function executeOperation(array $operation) * @return mixed * @throws LogicException if the operation is unsupported */ - private function executeOutcome(array $operation, array $outcome, $result, RuntimeException $exception = null) + private function executeOutcome(array $operation, array $outcome, $result, ?RuntimeException $exception = null) { $expectedError = array_key_exists('error', $outcome) ? $outcome['error'] : false; @@ -266,6 +277,7 @@ private function extractResultFromException(array $operation, array $outcome, Ru if ($exception instanceof BulkWriteException) { return new BulkWriteResult($exception->getWriteResult(), $insertedIds); } + break; case 'insertMany': @@ -274,6 +286,7 @@ private function extractResultFromException(array $operation, array $outcome, Ru if ($exception instanceof BulkWriteException) { return new InsertManyResult($exception->getWriteResult(), $insertedIds); } + break; } @@ -288,7 +301,7 @@ private function extractResultFromException(array $operation, array $outcome, Ru * @param mixed $actualResult * @throws LogicException if the operation is unsupported */ - private function executeAssertResult(array $operation, $expectedResult, $actualResult) + private function executeAssertResult(array $operation, $expectedResult, $actualResult): void { switch ($operation['name']) { case 'aggregate': @@ -301,6 +314,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR if (! is_last_pipeline_operator_write($operation['arguments']['pipeline'])) { $this->assertSameDocuments($expectedResult, $actualResult); } + break; case 'bulkWrite': @@ -340,6 +354,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR ['upsertedIds' => $actualResult->getUpsertedIds()] ); } + break; case 'count': @@ -367,6 +382,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR if (isset($expectedResult['deletedCount'])) { $this->assertSame($expectedResult['deletedCount'], $actualResult->getDeletedCount()); } + break; case 'findOneAndDelete': @@ -392,6 +408,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR ['insertedIds' => $actualResult->getInsertedIds()] ); } + break; case 'insertOne': @@ -408,6 +425,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR ['insertedId' => $actualResult->getInsertedId()] ); } + break; case 'replaceOne': @@ -434,6 +452,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR ['upsertedId' => $actualResult->getUpsertedId()] ); } + break; default: @@ -447,7 +466,7 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR * @param array $initialData * @param array $expectedData */ - private function initializeData(array $initialData, array $expectedData = null) + private function initializeData(array $initialData, ?array $expectedData = null): void { if (! empty($initialData)) { $this->collection->insertMany($initialData); @@ -464,7 +483,7 @@ private function initializeData(array $initialData, array $expectedData = null) * @param array $request * @return array */ - private function prepareBulkWriteRequest(array $request) + private function prepareBulkWriteRequest(array $request): array { switch ($request['name']) { case 'deleteMany': @@ -475,8 +494,10 @@ private function prepareBulkWriteRequest(array $request) array_diff_key($request['arguments'], ['filter' => 1]), ], ]; + case 'insertOne': - return [ 'insertOne' => [ $request['arguments']['document'] ]]; + return ['insertOne' => [$request['arguments']['document']]]; + case 'replaceOne': return [ 'replaceOne' => [ @@ -485,6 +506,7 @@ private function prepareBulkWriteRequest(array $request) array_diff_key($request['arguments'], ['filter' => 1, 'replacement' => 1]), ], ]; + case 'updateMany': case 'updateOne': return [ @@ -494,6 +516,7 @@ private function prepareBulkWriteRequest(array $request) array_diff_key($request['arguments'], ['filter' => 1, 'update' => 1]), ], ]; + default: throw new LogicException('Unsupported bulk write request: ' . $request['name']); } @@ -505,7 +528,7 @@ private function prepareBulkWriteRequest(array $request) * @param array $arguments * @return array */ - private function prepareFindAndModifyArguments(array $arguments) + private function prepareFindAndModifyArguments(array $arguments): array { if (isset($arguments['returnDocument'])) { $arguments['returnDocument'] = 'after' === strtolower($arguments['returnDocument']) diff --git a/tests/Collection/FunctionalTestCase.php b/tests/Collection/FunctionalTestCase.php index 7202e7d19..89aea89dc 100644 --- a/tests/Collection/FunctionalTestCase.php +++ b/tests/Collection/FunctionalTestCase.php @@ -13,7 +13,7 @@ abstract class FunctionalTestCase extends BaseFunctionalTestCase /** @var Collection */ protected $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -22,7 +22,7 @@ public function setUp() : void $this->dropCollection(); } - public function tearDown() : void + public function tearDown(): void { if ($this->hasFailed()) { return; diff --git a/tests/Command/ListCollectionsTest.php b/tests/Command/ListCollectionsTest.php index 333152561..85cabab3b 100644 --- a/tests/Command/ListCollectionsTest.php +++ b/tests/Command/ListCollectionsTest.php @@ -11,7 +11,7 @@ class ListCollectionsTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new ListCollections($this->getDatabaseName(), $options); diff --git a/tests/Command/ListDatabasesTest.php b/tests/Command/ListDatabasesTest.php index d2ce95623..c1036ae94 100644 --- a/tests/Command/ListDatabasesTest.php +++ b/tests/Command/ListDatabasesTest.php @@ -11,7 +11,7 @@ class ListDatabasesTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new ListDatabases($options); diff --git a/tests/CommandObserver.php b/tests/CommandObserver.php index 44d0fa4ef..2f5165138 100644 --- a/tests/CommandObserver.php +++ b/tests/CommandObserver.php @@ -7,6 +7,7 @@ use MongoDB\Driver\Monitoring\CommandSubscriber; use MongoDB\Driver\Monitoring\CommandSucceededEvent; use Throwable; + use function call_user_func; use function MongoDB\Driver\Monitoring\addSubscriber; use function MongoDB\Driver\Monitoring\removeSubscriber; @@ -19,7 +20,7 @@ class CommandObserver implements CommandSubscriber /** @var array */ private $commands = []; - public function observe(callable $execution, callable $commandCallback) + public function observe(callable $execution, callable $commandCallback): void { $this->commands = []; @@ -41,17 +42,17 @@ public function observe(callable $execution, callable $commandCallback) } } - public function commandStarted(CommandStartedEvent $event) + public function commandStarted(CommandStartedEvent $event): void { $this->commands[$event->getRequestId()]['started'] = $event; } - public function commandSucceeded(CommandSucceededEvent $event) + public function commandSucceeded(CommandSucceededEvent $event): void { $this->commands[$event->getRequestId()]['succeeded'] = $event; } - public function commandFailed(CommandFailedEvent $event) + public function commandFailed(CommandFailedEvent $event): void { $this->commands[$event->getRequestId()]['failed'] = $event; } diff --git a/tests/Database/CollectionManagementFunctionalTest.php b/tests/Database/CollectionManagementFunctionalTest.php index 246ceebb9..eac00bcc7 100644 --- a/tests/Database/CollectionManagementFunctionalTest.php +++ b/tests/Database/CollectionManagementFunctionalTest.php @@ -6,6 +6,7 @@ use MongoDB\Driver\BulkWrite; use MongoDB\Model\CollectionInfo; use MongoDB\Model\CollectionInfoIterator; + use function call_user_func; use function is_callable; use function sprintf; @@ -15,14 +16,14 @@ */ class CollectionManagementFunctionalTest extends FunctionalTestCase { - public function testCreateCollection() + public function testCreateCollection(): void { $that = $this; $basicCollectionName = $this->getCollectionName() . '.basic'; $commandResult = $this->database->createCollection($basicCollectionName); $this->assertCommandSucceeded($commandResult); - $this->assertCollectionExists($basicCollectionName, function (CollectionInfo $info) use ($that) { + $this->assertCollectionExists($basicCollectionName, function (CollectionInfo $info) use ($that): void { $that->assertFalse($info->isCapped()); }); @@ -35,14 +36,14 @@ public function testCreateCollection() $commandResult = $this->database->createCollection($cappedCollectionName, $cappedCollectionOptions); $this->assertCommandSucceeded($commandResult); - $this->assertCollectionExists($cappedCollectionName, function (CollectionInfo $info) use ($that) { + $this->assertCollectionExists($cappedCollectionName, function (CollectionInfo $info) use ($that): void { $that->assertTrue($info->isCapped()); $that->assertEquals(100, $info->getCappedMax()); $that->assertEquals(1048576, $info->getCappedSize()); }); } - public function testDropCollection() + public function testDropCollection(): void { $bulkWrite = new BulkWrite(); $bulkWrite->insert(['x' => 1]); @@ -55,7 +56,7 @@ public function testDropCollection() $this->assertCollectionCount($this->getNamespace(), 0); } - public function testListCollections() + public function testListCollections(): void { $commandResult = $this->database->createCollection($this->getCollectionName()); $this->assertCommandSucceeded($commandResult); @@ -68,7 +69,7 @@ public function testListCollections() } } - public function testListCollectionsWithFilter() + public function testListCollectionsWithFilter(): void { $commandResult = $this->database->createCollection($this->getCollectionName()); $this->assertCommandSucceeded($commandResult); @@ -85,7 +86,7 @@ public function testListCollectionsWithFilter() } } - public function testListCollectionNames() + public function testListCollectionNames(): void { $commandResult = $this->database->createCollection($this->getCollectionName()); $this->assertCommandSucceeded($commandResult); @@ -97,7 +98,7 @@ public function testListCollectionNames() } } - public function testListCollectionNamesWithFilter() + public function testListCollectionNamesWithFilter(): void { $commandResult = $this->database->createCollection($this->getCollectionName()); $this->assertCommandSucceeded($commandResult); @@ -122,7 +123,7 @@ public function testListCollectionNamesWithFilter() * * @param callable $callback */ - private function assertCollectionExists($collectionName, $callback = null) + private function assertCollectionExists($collectionName, ?callable $callback = null): void { if ($callback !== null && ! is_callable($callback)) { throw new InvalidArgumentException('$callback is not a callable'); diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 347abd9fd..0a0f1501d 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -10,6 +10,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Operation\CreateIndexes; + use function array_key_exists; use function current; @@ -21,7 +22,7 @@ class DatabaseFunctionalTest extends FunctionalTestCase /** * @dataProvider provideInvalidDatabaseNames */ - public function testConstructorDatabaseNameArgument($databaseName) + public function testConstructorDatabaseNameArgument($databaseName): void { $this->expectException(InvalidArgumentException::class); // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) @@ -39,7 +40,7 @@ public function provideInvalidDatabaseNames() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Database($this->manager, $this->getDatabaseName(), $options); @@ -68,22 +69,22 @@ public function provideInvalidConstructorOptions() return $options; } - public function testGetManager() + public function testGetManager(): void { $this->assertSame($this->manager, $this->database->getManager()); } - public function testToString() + public function testToString(): void { $this->assertEquals($this->getDatabaseName(), (string) $this->database); } - public function getGetDatabaseName() + public function getGetDatabaseName(): void { $this->assertEquals($this->getDatabaseName(), $this->database->getDatabaseName()); } - public function testCommand() + public function testCommand(): void { $command = ['ping' => 1]; $options = [ @@ -100,7 +101,7 @@ public function testCommand() $this->assertSame(1, (int) $commandResult->ok); } - public function testCommandDoesNotInheritReadPreference() + public function testCommandDoesNotInheritReadPreference(): void { if (! $this->isReplicaSet()) { $this->markTestSkipped('Test only applies to replica sets'); @@ -116,7 +117,7 @@ public function testCommandDoesNotInheritReadPreference() $this->assertTrue($cursor->getServer()->isPrimary()); } - public function testCommandAppliesTypeMapToCursor() + public function testCommandAppliesTypeMapToCursor(): void { $command = ['ping' => 1]; $options = [ @@ -138,13 +139,13 @@ public function testCommandAppliesTypeMapToCursor() /** * @dataProvider provideInvalidDocumentValues */ - public function testCommandCommandArgumentTypeCheck($command) + public function testCommandCommandArgumentTypeCheck($command): void { $this->expectException(InvalidArgumentException::class); $this->database->command($command); } - public function testDrop() + public function testDrop(): void { $bulkWrite = new BulkWrite(); $bulkWrite->insert(['x' => 1]); @@ -157,7 +158,7 @@ public function testDrop() $this->assertCollectionCount($this->getNamespace(), 0); } - public function testGetSelectsCollectionAndInheritsOptions() + public function testGetSelectsCollectionAndInheritsOptions(): void { $databaseOptions = ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; @@ -177,7 +178,7 @@ public function testGetSelectsCollectionAndInheritsOptions() * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-sharded_cluster * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ - public function testModifyCollection() + public function testModifyCollection(): void { $this->database->createCollection($this->getCollectionName()); @@ -210,7 +211,7 @@ public function testModifyCollection() } } - public function testSelectCollectionInheritsOptions() + public function testSelectCollectionInheritsOptions(): void { $databaseOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -236,7 +237,7 @@ public function testSelectCollectionInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectCollectionPassesOptions() + public function testSelectCollectionPassesOptions(): void { $collectionOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -258,7 +259,7 @@ public function testSelectCollectionPassesOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectGridFSBucketInheritsOptions() + public function testSelectGridFSBucketInheritsOptions(): void { $databaseOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -282,7 +283,7 @@ public function testSelectGridFSBucketInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testSelectGridFSBucketPassesOptions() + public function testSelectGridFSBucketPassesOptions(): void { $bucketOptions = [ 'bucketName' => 'custom_fs', @@ -307,7 +308,7 @@ public function testSelectGridFSBucketPassesOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testWithOptionsInheritsOptions() + public function testWithOptionsInheritsOptions(): void { $databaseOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), @@ -332,7 +333,7 @@ public function testWithOptionsInheritsOptions() $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); } - public function testWithOptionsPassesOptions() + public function testWithOptionsPassesOptions(): void { $databaseOptions = [ 'readConcern' => new ReadConcern(ReadConcern::LOCAL), diff --git a/tests/Database/FunctionalTestCase.php b/tests/Database/FunctionalTestCase.php index e3a4c48aa..5e0906731 100644 --- a/tests/Database/FunctionalTestCase.php +++ b/tests/Database/FunctionalTestCase.php @@ -13,7 +13,7 @@ abstract class FunctionalTestCase extends BaseFunctionalTestCase /** @var Database */ protected $database; - public function setUp() : void + public function setUp(): void { parent::setUp(); diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 008201189..2c8c54996 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -9,6 +9,7 @@ use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; + use function in_array; use function ob_end_clean; use function ob_start; @@ -24,14 +25,14 @@ */ class DocumentationExamplesTest extends FunctionalTestCase { - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->dropCollection(); } - public function tearDown() : void + public function tearDown(): void { if ($this->hasFailed()) { return; @@ -42,7 +43,7 @@ public function tearDown() : void parent::tearDown(); } - public function testExample_1_2() + public function testExample_1_2(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -66,7 +67,7 @@ public function testExample_1_2() $this->assertCursorCount(1, $cursor); } - public function testExample_3() + public function testExample_3(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -97,10 +98,11 @@ public function testExample_3() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(3); } - public function testExample_6_13() + public function testExample_6_13(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -143,6 +145,7 @@ public function testExample_6_13() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(5); // Start Example 7 @@ -203,7 +206,7 @@ public function testExample_6_13() $this->assertCursorCount(2, $cursor); } - public function testExample_14_19() + public function testExample_14_19(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -246,6 +249,7 @@ public function testExample_14_19() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(5); // Start Example 15 @@ -283,7 +287,7 @@ public function testExample_14_19() $this->assertCursorCount(1, $cursor); } - public function testExample_20_28() + public function testExample_20_28(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -326,6 +330,7 @@ public function testExample_20_28() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(5); // Start Example 21 @@ -389,7 +394,7 @@ public function testExample_20_28() $this->assertCursorCount(1, $cursor); } - public function testExample_29_37() + public function testExample_29_37(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -436,6 +441,7 @@ public function testExample_29_37() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(5); // Start Example 30 @@ -487,7 +493,7 @@ public function testExample_29_37() $this->assertCursorCount(2, $cursor); } - public function testExample_38_41() + public function testExample_38_41(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -502,6 +508,7 @@ public function testExample_38_41() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertIsInt($id); } + $this->assertInventoryCount(2); // Start Example 39 @@ -523,7 +530,7 @@ public function testExample_38_41() $this->assertCursorCount(1, $cursor); } - public function testExample_42_50() + public function testExample_42_50(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -577,6 +584,7 @@ public function testExample_42_50() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(5); // Start Example 43 @@ -604,6 +612,7 @@ public function testExample_42_50() foreach (['_id', 'item', 'status'] as $field) { $this->assertObjectHasAttribute($field, $document); } + foreach (['size', 'instock'] as $field) { $this->assertObjectNotHasAttribute($field, $document); } @@ -622,6 +631,7 @@ public function testExample_42_50() foreach (['item', 'status'] as $field) { $this->assertObjectHasAttribute($field, $document); } + foreach (['_id', 'size', 'instock'] as $field) { $this->assertObjectNotHasAttribute($field, $document); } @@ -640,6 +650,7 @@ public function testExample_42_50() foreach (['_id', 'item', 'size'] as $field) { $this->assertObjectHasAttribute($field, $document); } + foreach (['status', 'instock'] as $field) { $this->assertObjectNotHasAttribute($field, $document); } @@ -658,6 +669,7 @@ public function testExample_42_50() foreach (['_id', 'item', 'status', 'size'] as $field) { $this->assertObjectHasAttribute($field, $document); } + $this->assertObjectNotHasAttribute('instock', $document); $this->assertObjectHasAttribute('uom', $document->size); $this->assertObjectNotHasAttribute('h', $document->size); @@ -677,6 +689,7 @@ public function testExample_42_50() foreach (['_id', 'item', 'status', 'size', 'instock'] as $field) { $this->assertObjectHasAttribute($field, $document); } + $this->assertObjectHasAttribute('h', $document->size); $this->assertObjectHasAttribute('w', $document->size); $this->assertObjectNotHasAttribute('uom', $document->size); @@ -695,6 +708,7 @@ public function testExample_42_50() foreach (['_id', 'item', 'status', 'instock'] as $field) { $this->assertObjectHasAttribute($field, $document); } + $this->assertObjectNotHasAttribute('size', $document); foreach ($document->instock as $instock) { $this->assertObjectHasAttribute('qty', $instock); @@ -715,12 +729,13 @@ public function testExample_42_50() foreach (['_id', 'item', 'status', 'instock'] as $field) { $this->assertObjectHasAttribute($field, $document); } + $this->assertObjectNotHasAttribute('size', $document); $this->assertCount(1, $document->instock); } } - public function testExample_51_54() + public function testExample_51_54(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -793,6 +808,7 @@ public function testExample_51_54() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(10); // Start Example 52 @@ -860,7 +876,7 @@ public function testExample_51_54() $this->assertCursorCount(1, $cursor); } - public function testExample_55_58() + public function testExample_55_58(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -903,6 +919,7 @@ public function testExample_55_58() foreach ($insertManyResult->getInsertedIds() as $id) { $this->assertInstanceOf(ObjectId::class, $id); } + $this->assertInventoryCount(5); // Start Example 57 @@ -930,7 +947,7 @@ public function testExample_55_58() } /** @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ - public function testChangeStreamExample_1_4() + public function testChangeStreamExample_1_4(): void { $this->skipIfChangeStreamIsNotSupported(); @@ -1036,7 +1053,7 @@ public function testChangeStreamExample_1_4() $this->assertNull($secondChange); } - public function testAggregation_example_1() + public function testAggregation_example_1(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -1050,7 +1067,7 @@ public function testAggregation_example_1() $this->assertInstanceOf(Cursor::class, $cursor); } - public function testAggregation_example_2() + public function testAggregation_example_2(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -1078,7 +1095,7 @@ public function testAggregation_example_2() $this->assertInstanceOf(Cursor::class, $cursor); } - public function testAggregation_example_3() + public function testAggregation_example_3(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -1116,7 +1133,7 @@ public function testAggregation_example_3() $this->assertInstanceOf(Cursor::class, $cursor); } - public function testAggregation_example_4() + public function testAggregation_example_4(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('$lookup does not support "let" option'); @@ -1124,6 +1141,7 @@ public function testAggregation_example_4() $db = new Database($this->manager, $this->getDatabaseName()); + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps // Start Aggregation Example 4 $cursor = $db->air_alliances->aggregate([ [ @@ -1154,11 +1172,12 @@ public function testAggregation_example_4() ], ]); // End Aggregation Example 4 + // phpcs:enable $this->assertInstanceOf(Cursor::class, $cursor); } - public function testRunCommand_example_1() + public function testRunCommand_example_1(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -1170,7 +1189,7 @@ public function testRunCommand_example_1() $this->assertInstanceOf(Cursor::class, $cursor); } - public function testRunCommand_example_2() + public function testRunCommand_example_2(): void { $db = new Database($this->manager, $this->getDatabaseName()); $db->dropCollection('restaurants'); @@ -1184,7 +1203,7 @@ public function testRunCommand_example_2() $this->assertInstanceOf(Cursor::class, $cursor); } - public function testIndex_example_1() + public function testIndex_example_1(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -1195,7 +1214,7 @@ public function testIndex_example_1() $this->assertEquals('score_1', $indexName); } - public function testIndex_example_2() + public function testIndex_example_2(): void { $db = new Database($this->manager, $this->getDatabaseName()); @@ -1213,7 +1232,7 @@ public function testIndex_example_2() // phpcs:disable Squiz.Commenting.FunctionComment.WrongStyle // phpcs:disable Squiz.WhiteSpace.FunctionSpacing.After // Start Transactions Intro Example 1 - private function updateEmployeeInfo1(\MongoDB\Client $client, \MongoDB\Driver\Session $session) + private function updateEmployeeInfo1(\MongoDB\Client $client, \MongoDB\Driver\Session $session): void { $session->startTransaction([ 'readConcern' => new \MongoDB\Driver\ReadConcern('snapshot'), @@ -1227,12 +1246,13 @@ private function updateEmployeeInfo1(\MongoDB\Client $client, \MongoDB\Driver\Se ['session' => $session] ); $client->reporting->events->insertOne( - ['employee' => 3, 'status' => [ 'new' => 'Inactive', 'old' => 'Active']], + ['employee' => 3, 'status' => ['new' => 'Inactive', 'old' => 'Active']], ['session' => $session] ); } catch (\MongoDB\Driver\Exception\Exception $error) { echo "Caught exception during transaction, aborting.\n"; $session->abortTransaction(); + throw $error; } @@ -1249,10 +1269,12 @@ private function updateEmployeeInfo1(\MongoDB\Client $client, \MongoDB\Driver\Se continue; } else { echo "Error during commit ...\n"; + throw $error; } } catch (\MongoDB\Driver\Exception\Exception $error) { echo "Error during commit ...\n"; + throw $error; } } @@ -1260,7 +1282,7 @@ private function updateEmployeeInfo1(\MongoDB\Client $client, \MongoDB\Driver\Se // End Transactions Intro Example 1 // phpcs:enable - public function testTransactions_intro_example_1() + public function testTransactions_intro_example_1(): void { $this->skipIfTransactionsAreNotSupported(); @@ -1290,7 +1312,7 @@ public function testTransactions_intro_example_1() // phpcs:disable Squiz.Commenting.FunctionComment.WrongStyle // phpcs:disable Squiz.WhiteSpace.FunctionSpacing.After // Start Transactions Retry Example 1 - private function runTransactionWithRetry1(callable $txnFunc, \MongoDB\Client $client, \MongoDB\Driver\Session $session) + private function runTransactionWithRetry1(callable $txnFunc, \MongoDB\Client $client, \MongoDB\Driver\Session $session): void { while (true) { try { @@ -1319,7 +1341,7 @@ private function runTransactionWithRetry1(callable $txnFunc, \MongoDB\Client $cl // phpcs:disable Squiz.Commenting.FunctionComment.WrongStyle // phpcs:disable Squiz.WhiteSpace.FunctionSpacing.After // Start Transactions Retry Example 2 - private function commitWithRetry2(\MongoDB\Driver\Session $session) + private function commitWithRetry2(\MongoDB\Driver\Session $session): void { while (true) { try { @@ -1334,10 +1356,12 @@ private function commitWithRetry2(\MongoDB\Driver\Session $session) continue; } else { echo "Error during commit ...\n"; + throw $error; } } catch (\MongoDB\Driver\Exception\Exception $error) { echo "Error during commit ...\n"; + throw $error; } } @@ -1349,7 +1373,7 @@ private function commitWithRetry2(\MongoDB\Driver\Session $session) // phpcs:disable Squiz.Commenting.FunctionComment.WrongStyle // phpcs:disable Squiz.WhiteSpace.FunctionSpacing.After // Start Transactions Retry Example 3 - private function runTransactionWithRetry3(callable $txnFunc, \MongoDB\Client $client, \MongoDB\Driver\Session $session) + private function runTransactionWithRetry3(callable $txnFunc, \MongoDB\Client $client, \MongoDB\Driver\Session $session): void { while (true) { try { @@ -1370,7 +1394,7 @@ private function runTransactionWithRetry3(callable $txnFunc, \MongoDB\Client $cl } } - private function commitWithRetry3(\MongoDB\Driver\Session $session) + private function commitWithRetry3(\MongoDB\Driver\Session $session): void { while (true) { try { @@ -1385,16 +1409,18 @@ private function commitWithRetry3(\MongoDB\Driver\Session $session) continue; } else { echo "Error during commit ...\n"; + throw $error; } } catch (\MongoDB\Driver\Exception\Exception $error) { echo "Error during commit ...\n"; + throw $error; } } } - private function updateEmployeeInfo3(\MongoDB\Client $client, \MongoDB\Driver\Session $session) + private function updateEmployeeInfo3(\MongoDB\Client $client, \MongoDB\Driver\Session $session): void { $session->startTransaction([ 'readConcern' => new \MongoDB\Driver\ReadConcern("snapshot"), @@ -1409,19 +1435,20 @@ private function updateEmployeeInfo3(\MongoDB\Client $client, \MongoDB\Driver\Se ['session' => $session] ); $client->reporting->events->insertOne( - ['employee' => 3, 'status' => [ 'new' => 'Inactive', 'old' => 'Active']], + ['employee' => 3, 'status' => ['new' => 'Inactive', 'old' => 'Active']], ['session' => $session] ); } catch (\MongoDB\Driver\Exception\Exception $error) { echo "Caught exception during transaction, aborting.\n"; $session->abortTransaction(); + throw $error; } $this->commitWithRetry3($session); } - private function doUpdateEmployeeInfo(\MongoDB\Client $client) + private function doUpdateEmployeeInfo(\MongoDB\Client $client): void { // Start a session. $session = $client->startSession(); @@ -1435,7 +1462,7 @@ private function doUpdateEmployeeInfo(\MongoDB\Client $client) // End Transactions Retry Example 3 // phpcs:enable - public function testTransactions_retry_example_3() + public function testTransactions_retry_example_3(): void { $this->skipIfTransactionsAreNotSupported(); @@ -1459,7 +1486,7 @@ public function testTransactions_retry_example_3() } } - public function testCausalConsistency() + public function testCausalConsistency(): void { $this->skipIfCausalConsistencyIsNotSupported(); @@ -1469,12 +1496,12 @@ public function testCausalConsistency() $client = static::createTestClient(); $items = $client->selectDatabase( 'test', - [ 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY) ] + ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] )->items; $items->drop(); $items->insertOne( - [ 'sku' => '111', 'name' => 'Peanuts', 'start' => new UTCDateTime() ] + ['sku' => '111', 'name' => 'Peanuts', 'start' => new UTCDateTime()] ); try { @@ -1498,19 +1525,19 @@ public function testCausalConsistency() )->items; $s1 = $client->startSession( - [ 'causalConsistency' => true ] + ['causalConsistency' => true] ); $currentDate = new \MongoDB\BSON\UTCDateTime(); $items->updateOne( - [ 'sku' => '111', 'end' => [ '$exists' => false ] ], - [ '$set' => [ 'end' => $currentDate ] ], - [ 'session' => $s1 ] + ['sku' => '111', 'end' => ['$exists' => false]], + ['$set' => ['end' => $currentDate]], + ['session' => $s1] ); $items->insertOne( - [ 'sku' => '111-nuts', 'name' => 'Pecans', 'start' => $currentDate ], - [ 'session' => $s1 ] + ['sku' => '111-nuts', 'name' => 'Pecans', 'start' => $currentDate], + ['session' => $s1] ); // End Causal Consistency Example 1 // phpcs:enable @@ -1520,7 +1547,7 @@ public function testCausalConsistency() // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly // Start Causal Consistency Example 2 $s2 = $client->startSession( - [ 'causalConsistency' => true ] + ['causalConsistency' => true] ); $s2->advanceClusterTime($s1->getClusterTime()); $s2->advanceOperationTime($s1->getOperationTime()); @@ -1535,12 +1562,13 @@ public function testCausalConsistency() )->items; $result = $items->find( - [ 'end' => [ '$exists' => false ] ], - [ 'session' => $s2 ] + ['end' => ['$exists' => false]], + ['session' => $s2] ); foreach ($result as $item) { var_dump($item); } + // End Causal Consistency Example 2 // phpcs:enable @@ -1550,7 +1578,7 @@ public function testCausalConsistency() /** * @doesNotPerformAssertions */ - public function testVersionedApi() + public function testVersionedApi(): void { $uriString = static::getUri(true); @@ -1580,7 +1608,7 @@ public function testVersionedApi() /** * @doesNotPerformAssertions */ - public function testWithTransactionExample() + public function testWithTransactionExample(): void { $this->skipIfTransactionsAreNotSupported(); @@ -1616,7 +1644,7 @@ public function testWithTransactionExample() // Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. - $callback = function (\MongoDB\Driver\Session $session) use ($client) { + $callback = function (\MongoDB\Driver\Session $session) use ($client): void { $client ->selectCollection('mydb1', 'foo') ->insertOne(['abc' => 1], ['session' => $session]); @@ -1649,17 +1677,17 @@ public function testWithTransactionExample() * * @return string */ - protected function getCollectionName() + protected function getCollectionName(): string { return 'inventory'; } - private function assertCursorCount($count, Cursor $cursor) + private function assertCursorCount($count, Cursor $cursor): void { $this->assertCount($count, $cursor->toArray()); } - private function assertInventoryCount($count) + private function assertInventoryCount($count): void { $this->assertCollectionCount($this->getDatabaseName() . '.' . $this->getCollectionName(), $count); } diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 19d6b5d49..44c51d8c6 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -18,6 +18,7 @@ use MongoDB\Operation\DropCollection; use stdClass; use UnexpectedValueException; + use function array_merge; use function count; use function current; @@ -37,6 +38,7 @@ use function preg_replace; use function sprintf; use function version_compare; + use const INFO_MODULES; abstract class FunctionalTestCase extends TestCase @@ -47,7 +49,7 @@ abstract class FunctionalTestCase extends TestCase /** @var array */ private $configuredFailPoints = []; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -55,24 +57,24 @@ public function setUp() : void $this->configuredFailPoints = []; } - public function tearDown() : void + public function tearDown(): void { $this->disableFailPoints(); parent::tearDown(); } - public static function createTestClient(string $uri = null, array $options = [], array $driverOptions = []) : Client + public static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client { return new Client($uri ?? static::getUri(), $options, static::appendServerApiOption($driverOptions)); } - public static function createTestManager(string $uri = null, array $options = [], array $driverOptions = []) : Manager + public static function createTestManager(?string $uri = null, array $options = [], array $driverOptions = []): Manager { return new Manager($uri ?? static::getUri(), $options, static::appendServerApiOption($driverOptions)); } - public static function getUri($allowMultipleMongoses = false) + public static function getUri($allowMultipleMongoses = false): string { $uri = parent::getUri(); @@ -103,7 +105,7 @@ public static function getUri($allowMultipleMongoses = false) // Re-append port to last host if (isset($urlParts['port'])) { - $hosts[$numHosts-1] .= ':' . $urlParts['port']; + $hosts[$numHosts - 1] .= ':' . $urlParts['port']; } $parts = ['mongodb://']; @@ -122,6 +124,7 @@ public static function getUri($allowMultipleMongoses = false) if (isset($urlParts['path'])) { $parts[] = $urlParts['path']; } + if (isset($urlParts['query'])) { $parts = array_merge($parts, [ '?', @@ -132,9 +135,9 @@ public static function getUri($allowMultipleMongoses = false) return implode('', $parts); } - protected function assertCollectionCount($namespace, $count) + protected function assertCollectionCount($namespace, $count): void { - list($databaseName, $collectionName) = explode('.', $namespace, 2); + [$databaseName, $collectionName] = explode('.', $namespace, 2); $cursor = $this->manager->executeCommand($databaseName, new Command(['count' => $collectionName])); $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); @@ -144,7 +147,7 @@ protected function assertCollectionCount($namespace, $count) $this->assertEquals($count, $document['n']); } - protected function assertCommandSucceeded($document) + protected function assertCommandSucceeded($document): void { $document = is_object($document) ? (array) $document : $document; @@ -152,7 +155,7 @@ protected function assertCommandSucceeded($document) $this->assertEquals(1, $document['ok']); } - protected function assertSameObjectId($expectedObjectId, $actualObjectId) + protected function assertSameObjectId($expectedObjectId, $actualObjectId): void { $this->assertInstanceOf(ObjectId::class, $expectedObjectId); $this->assertInstanceOf(ObjectId::class, $actualObjectId); @@ -168,7 +171,7 @@ protected function assertSameObjectId($expectedObjectId, $actualObjectId) * @param array|stdClass $command configureFailPoint command document * @throws InvalidArgumentException if $command is not a configureFailPoint command */ - public function configureFailPoint($command, Server $server = null) + public function configureFailPoint($command, ?Server $server = null): void { if (! $this->isFailCommandSupported()) { $this->markTestSkipped('failCommand is only supported on mongod >= 4.0.0 and mongos >= 4.1.5.'); @@ -211,7 +214,7 @@ public function configureFailPoint($command, Server $server = null) * * @param array $options */ - protected function createCollection(array $options = []) + protected function createCollection(array $options = []): void { if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; @@ -230,7 +233,7 @@ protected function createCollection(array $options = []) * * @param array $options */ - protected function dropCollection(array $options = []) + protected function dropCollection(array $options = []): void { if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; @@ -240,7 +243,7 @@ protected function dropCollection(array $options = []) $operation->execute($this->getPrimaryServer()); } - protected function getFeatureCompatibilityVersion(ReadPreference $readPreference = null) + protected function getFeatureCompatibilityVersion(?ReadPreference $readPreference = null) { if ($this->isShardedCluster()) { return $this->getServerVersion($readPreference); @@ -277,7 +280,7 @@ protected function getPrimaryServer() return $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); } - protected function getServerVersion(ReadPreference $readPreference = null) + protected function getServerVersion(?ReadPreference $readPreference = null) { $buildInfo = $this->manager->executeCommand( $this->getDatabaseName(), @@ -292,7 +295,7 @@ protected function getServerVersion(ReadPreference $readPreference = null) throw new UnexpectedValueException('Could not determine server version'); } - protected function getServerStorageEngine(ReadPreference $readPreference = null) + protected function getServerStorageEngine(?ReadPreference $readPreference = null) { $cursor = $this->manager->executeCommand( $this->getDatabaseName(), @@ -341,22 +344,25 @@ protected function isShardedClusterUsingReplicasets() return preg_match('@^.*/.*:\d+@', $document['host']); } - protected function skipIfChangeStreamIsNotSupported() + protected function skipIfChangeStreamIsNotSupported(): void { switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_MONGOS: if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('$changeStream is only supported on MongoDB 3.6 or higher'); } + if (! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('$changeStream is only supported with replicasets'); } + break; case Server::TYPE_RS_PRIMARY: if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { $this->markTestSkipped('$changeStream is only supported on FCV 3.6 or higher'); } + break; default: @@ -364,25 +370,29 @@ protected function skipIfChangeStreamIsNotSupported() } } - protected function skipIfCausalConsistencyIsNotSupported() + protected function skipIfCausalConsistencyIsNotSupported(): void { switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_MONGOS: if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Causal Consistency is only supported on MongoDB 3.6 or higher'); } + if (! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('Causal Consistency is only supported with replicasets'); } + break; case Server::TYPE_RS_PRIMARY: if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { $this->markTestSkipped('Causal Consistency is only supported on FCV 3.6 or higher'); } + if ($this->getServerStorageEngine() !== 'wiredTiger') { $this->markTestSkipped('Causal Consistency requires WiredTiger storage engine'); } + break; default: @@ -390,7 +400,7 @@ protected function skipIfCausalConsistencyIsNotSupported() } } - protected function skipIfClientSideEncryptionIsNotSupported() + protected function skipIfClientSideEncryptionIsNotSupported(): void { if (version_compare($this->getFeatureCompatibilityVersion(), '4.2', '<')) { $this->markTestSkipped('Client Side Encryption only supported on FCV 4.2 or higher'); @@ -401,14 +411,14 @@ protected function skipIfClientSideEncryptionIsNotSupported() } } - protected function skipIfGeoHaystackIndexIsNotSupported() + protected function skipIfGeoHaystackIndexIsNotSupported(): void { if (version_compare($this->getServerVersion(), '4.9', '>=')) { $this->markTestSkipped('GeoHaystack indexes cannot be created in version 4.9 and above'); } } - protected function skipIfTransactionsAreNotSupported() + protected function skipIfTransactionsAreNotSupported(): void { if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) { $this->markTestSkipped('Transactions are not supported on standalone servers'); @@ -435,7 +445,7 @@ protected function skipIfTransactionsAreNotSupported() } } - private static function appendServerApiOption(array $driverOptions) : array + private static function appendServerApiOption(array $driverOptions): array { if (getenv('API_VERSION') && ! isset($driverOptions['serverApi'])) { $driverOptions['serverApi'] = new ServerApi(getenv('API_VERSION')); @@ -450,24 +460,19 @@ private static function appendServerApiOption(array $driverOptions) : array * This tracks fail points set via configureFailPoint() and should be called * during tearDown(). */ - private function disableFailPoints() + private function disableFailPoints(): void { if (empty($this->configuredFailPoints)) { return; } - foreach ($this->configuredFailPoints as list($failPoint, $server)) { + foreach ($this->configuredFailPoints as [$failPoint, $server]) { $operation = new DatabaseCommand('admin', ['configureFailPoint' => $failPoint, 'mode' => 'off']); $operation->execute($server); } } - /** - * @param string $row - * - * @return string|null - */ - private function getModuleInfo($row) + private function getModuleInfo(string $row): ?string { ob_start(); phpinfo(INFO_MODULES); @@ -487,7 +492,7 @@ private function getModuleInfo($row) * * @return bool */ - private function isFailCommandSupported() + private function isFailCommandSupported(): bool { $minVersion = $this->isShardedCluster() ? '4.1.5' : '4.0.0'; @@ -499,7 +504,7 @@ private function isFailCommandSupported() * * @return bool */ - private function isFailCommandEnabled() + private function isFailCommandEnabled(): bool { try { $cursor = $this->manager->executeCommand( diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index 6efba64b1..1644ecb73 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -5,6 +5,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Model\BSONArray; use MongoDB\Model\BSONDocument; + use function MongoDB\apply_type_map_to_document; use function MongoDB\create_field_path_type_map; use function MongoDB\generate_index_name; @@ -20,7 +21,7 @@ class FunctionsTest extends TestCase /** * @dataProvider provideDocumentAndTypeMap */ - public function testApplyTypeMapToDocument($document, array $typeMap, $expectedDocument) + public function testApplyTypeMapToDocument($document, array $typeMap, $expectedDocument): void { $this->assertEquals($expectedDocument, apply_type_map_to_document($document, $typeMap)); } @@ -92,7 +93,7 @@ public function provideDocumentAndTypeMap() /** * @dataProvider provideIndexSpecificationDocumentsAndGeneratedNames */ - public function testGenerateIndexName($document, $expectedName) + public function testGenerateIndexName($document, $expectedName): void { $this->assertSame($expectedName, generate_index_name($document)); } @@ -111,7 +112,7 @@ public function provideIndexSpecificationDocumentsAndGeneratedNames() /** * @dataProvider provideInvalidDocumentValues */ - public function testGenerateIndexNameArgumentTypeCheck($document) + public function testGenerateIndexNameArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); generate_index_name($document); @@ -120,7 +121,7 @@ public function testGenerateIndexNameArgumentTypeCheck($document) /** * @dataProvider provideIsFirstKeyOperatorDocuments */ - public function testIsFirstKeyOperator($document, $isFirstKeyOperator) + public function testIsFirstKeyOperator($document, $isFirstKeyOperator): void { $this->assertSame($isFirstKeyOperator, is_first_key_operator($document)); } @@ -140,7 +141,7 @@ public function provideIsFirstKeyOperatorDocuments() /** * @dataProvider provideInvalidDocumentValues */ - public function testIsFirstKeyOperatorArgumentTypeCheck($document) + public function testIsFirstKeyOperatorArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); is_first_key_operator($document); @@ -149,7 +150,7 @@ public function testIsFirstKeyOperatorArgumentTypeCheck($document) /** * @dataProvider provideMapReduceOutValues */ - public function testIsMapReduceOutputInline($out, $isInline) + public function testIsMapReduceOutputInline($out, $isInline): void { $this->assertSame($isInline, is_mapreduce_output_inline($out)); } @@ -167,7 +168,7 @@ public function provideMapReduceOutValues() /** * @dataProvider provideTypeMapValues */ - public function testCreateFieldPathTypeMap(array $expected, array $typeMap, $fieldPath = 'field') + public function testCreateFieldPathTypeMap(array $expected, array $typeMap, $fieldPath = 'field'): void { $this->assertEquals($expected, create_field_path_type_map($typeMap, $fieldPath)); } @@ -229,7 +230,7 @@ public function provideTypeMapValues() /** * @dataProvider providePipelines */ - public function testIsPipeline($expected, $pipeline) + public function testIsPipeline($expected, $pipeline): void { $this->assertSame($expected, is_pipeline($pipeline)); } diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 069b79b91..6ed7f27c8 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -16,6 +16,7 @@ use MongoDB\Operation\ListCollections; use MongoDB\Operation\ListIndexes; use PHPUnit\Framework\Error\Warning; + use function array_merge; use function call_user_func; use function current; @@ -34,6 +35,7 @@ use function strlen; use function strncasecmp; use function substr; + use const PHP_EOL; use const PHP_OS; use const PHP_VERSION_ID; @@ -46,7 +48,7 @@ class BucketFunctionalTest extends FunctionalTestCase /** * @doesNotPerformAssertions */ - public function testValidConstructorOptions() + public function testValidConstructorOptions(): void { new Bucket($this->manager, $this->getDatabaseName(), [ 'bucketName' => 'test', @@ -60,7 +62,7 @@ public function testValidConstructorOptions() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Bucket($this->manager, $this->getDatabaseName(), $options); @@ -101,7 +103,7 @@ public function provideInvalidConstructorOptions() return $options; } - public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive() + public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected "chunkSizeBytes" option to be >= 1, 0 given'); @@ -111,7 +113,7 @@ public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive() /** * @dataProvider provideInputDataAndExpectedChunks */ - public function testDelete($input, $expectedChunks) + public function testDelete($input, $expectedChunks): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); @@ -140,7 +142,7 @@ public function provideInputDataAndExpectedChunks() ]; } - public function testDeleteShouldRequireFileToExist() + public function testDeleteShouldRequireFileToExist(): void { $this->expectException(FileNotFoundException::class); $this->bucket->delete('nonexistent-id'); @@ -149,7 +151,7 @@ public function testDeleteShouldRequireFileToExist() /** * @dataProvider provideInputDataAndExpectedChunks */ - public function testDeleteStillRemovesChunksIfFileDoesNotExist($input, $expectedChunks) + public function testDeleteStillRemovesChunksIfFileDoesNotExist($input, $expectedChunks): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); @@ -167,7 +169,7 @@ public function testDeleteStillRemovesChunksIfFileDoesNotExist($input, $expected $this->assertCollectionCount($this->chunksCollection, 0); } - public function testDownloadingFileWithMissingChunk() + public function testDownloadingFileWithMissingChunk(): void { $id = $this->bucket->uploadFromStream("filename", $this->createStream("foobar")); @@ -177,7 +179,7 @@ public function testDownloadingFileWithMissingChunk() stream_get_contents($this->bucket->openDownloadStream($id)); } - public function testDownloadingFileWithUnexpectedChunkIndex() + public function testDownloadingFileWithUnexpectedChunkIndex(): void { $id = $this->bucket->uploadFromStream("filename", $this->createStream("foobar")); @@ -190,7 +192,7 @@ public function testDownloadingFileWithUnexpectedChunkIndex() stream_get_contents($this->bucket->openDownloadStream($id)); } - public function testDownloadingFileWithUnexpectedChunkSize() + public function testDownloadingFileWithUnexpectedChunkSize(): void { $id = $this->bucket->uploadFromStream("filename", $this->createStream("foobar")); @@ -206,7 +208,7 @@ public function testDownloadingFileWithUnexpectedChunkSize() /** * @dataProvider provideInputDataAndExpectedChunks */ - public function testDownloadToStream($input) + public function testDownloadToStream($input): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); $destination = $this->createStream(); @@ -218,7 +220,7 @@ public function testDownloadToStream($input) /** * @dataProvider provideInvalidStreamValues */ - public function testDownloadToStreamShouldRequireDestinationStream($destination) + public function testDownloadToStreamShouldRequireDestinationStream($destination): void { $this->expectException(InvalidArgumentException::class); $this->bucket->downloadToStream('id', $destination); @@ -229,13 +231,13 @@ public function provideInvalidStreamValues() return $this->wrapValuesForDataProvider($this->getInvalidStreamValues()); } - public function testDownloadToStreamShouldRequireFileToExist() + public function testDownloadToStreamShouldRequireFileToExist(): void { $this->expectException(FileNotFoundException::class); $this->bucket->downloadToStream('nonexistent-id', $this->createStream()); } - public function testDownloadToStreamByName() + public function testDownloadToStreamByName(): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo')); $this->bucket->uploadFromStream('filename', $this->createStream('bar')); @@ -273,7 +275,7 @@ public function testDownloadToStreamByName() /** * @dataProvider provideInvalidStreamValues */ - public function testDownloadToStreamByNameShouldRequireDestinationStream($destination) + public function testDownloadToStreamByNameShouldRequireDestinationStream($destination): void { $this->expectException(InvalidArgumentException::class); $this->bucket->downloadToStreamByName('filename', $destination); @@ -282,7 +284,7 @@ public function testDownloadToStreamByNameShouldRequireDestinationStream($destin /** * @dataProvider provideNonexistentFilenameAndRevision */ - public function testDownloadToStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision) + public function testDownloadToStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo')); $this->bucket->uploadFromStream('filename', $this->createStream('bar')); @@ -302,7 +304,7 @@ public function provideNonexistentFilenameAndRevision() ]; } - public function testDrop() + public function testDrop(): void { $this->bucket->uploadFromStream('filename', $this->createStream('foobar')); @@ -315,7 +317,7 @@ public function testDrop() $this->assertCollectionDoesNotExist($this->chunksCollection->getCollectionName()); } - public function testFind() + public function testFind(): void { $this->bucket->uploadFromStream('a', $this->createStream('foo')); $this->bucket->uploadFromStream('b', $this->createStream('foobar')); @@ -341,7 +343,7 @@ public function testFind() $this->assertSameDocuments($expected, $cursor); } - public function testFindUsesTypeMap() + public function testFindUsesTypeMap(): void { $this->bucket->uploadFromStream('a', $this->createStream('foo')); @@ -351,7 +353,7 @@ public function testFindUsesTypeMap() $this->assertInstanceOf(BSONDocument::class, $fileDocument); } - public function testFindOne() + public function testFindOne(): void { $this->bucket->uploadFromStream('a', $this->createStream('foo')); $this->bucket->uploadFromStream('b', $this->createStream('foobar')); @@ -373,19 +375,19 @@ public function testFindOne() $this->assertSameDocument(['filename' => 'b', 'length' => 6], $fileDocument); } - public function testGetBucketNameWithCustomValue() + public function testGetBucketNameWithCustomValue(): void { $bucket = new Bucket($this->manager, $this->getDatabaseName(), ['bucketName' => 'custom_fs']); $this->assertEquals('custom_fs', $bucket->getBucketName()); } - public function testGetBucketNameWithDefaultValue() + public function testGetBucketNameWithDefaultValue(): void { $this->assertEquals('fs', $this->bucket->getBucketName()); } - public function testGetChunksCollection() + public function testGetChunksCollection(): void { $chunksCollection = $this->bucket->getChunksCollection(); @@ -393,24 +395,24 @@ public function testGetChunksCollection() $this->assertEquals('fs.chunks', $chunksCollection->getCollectionName()); } - public function testGetChunkSizeBytesWithCustomValue() + public function testGetChunkSizeBytesWithCustomValue(): void { $bucket = new Bucket($this->manager, $this->getDatabaseName(), ['chunkSizeBytes' => 8192]); $this->assertEquals(8192, $bucket->getChunkSizeBytes()); } - public function testGetChunkSizeBytesWithDefaultValue() + public function testGetChunkSizeBytesWithDefaultValue(): void { $this->assertEquals(261120, $this->bucket->getChunkSizeBytes()); } - public function testGetDatabaseName() + public function testGetDatabaseName(): void { $this->assertEquals($this->getDatabaseName(), $this->bucket->getDatabaseName()); } - public function testGetFileDocumentForStreamUsesTypeMap() + public function testGetFileDocumentForStreamUsesTypeMap(): void { $metadata = ['foo' => 'bar']; $stream = $this->bucket->openUploadStream('filename', ['_id' => 1, 'metadata' => $metadata]); @@ -422,7 +424,7 @@ public function testGetFileDocumentForStreamUsesTypeMap() $this->assertSame(['foo' => 'bar'], $fileDocument['metadata']->getArrayCopy()); } - public function testGetFileDocumentForStreamWithReadableStream() + public function testGetFileDocumentForStreamWithReadableStream(): void { $metadata = ['foo' => 'bar']; $id = $this->bucket->uploadFromStream('filename', $this->createStream('foobar'), ['metadata' => $metadata]); @@ -436,7 +438,7 @@ public function testGetFileDocumentForStreamWithReadableStream() $this->assertSameDocument($metadata, $fileDocument->metadata); } - public function testGetFileDocumentForStreamWithWritableStream() + public function testGetFileDocumentForStreamWithWritableStream(): void { $metadata = ['foo' => 'bar']; $stream = $this->bucket->openUploadStream('filename', ['_id' => 1, 'metadata' => $metadata]); @@ -451,7 +453,7 @@ public function testGetFileDocumentForStreamWithWritableStream() /** * @dataProvider provideInvalidGridFSStreamValues */ - public function testGetFileDocumentForStreamShouldRequireGridFSStreamResource($stream) + public function testGetFileDocumentForStreamShouldRequireGridFSStreamResource($stream): void { $this->expectException(InvalidArgumentException::class); $this->bucket->getFileDocumentForStream($stream); @@ -462,7 +464,7 @@ public function provideInvalidGridFSStreamValues() return $this->wrapValuesForDataProvider(array_merge($this->getInvalidStreamValues(), [$this->createStream()])); } - public function testGetFileIdForStreamUsesTypeMap() + public function testGetFileIdForStreamUsesTypeMap(): void { $stream = $this->bucket->openUploadStream('filename', ['_id' => ['x' => 1]]); @@ -472,7 +474,7 @@ public function testGetFileIdForStreamUsesTypeMap() $this->assertSame(['x' => 1], $id->getArrayCopy()); } - public function testGetFileIdForStreamWithReadableStream() + public function testGetFileIdForStreamWithReadableStream(): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream('foobar')); $stream = $this->bucket->openDownloadStream($id); @@ -480,7 +482,7 @@ public function testGetFileIdForStreamWithReadableStream() $this->assertSameObjectId($id, $this->bucket->getFileIdForStream($stream)); } - public function testGetFileIdForStreamWithWritableStream() + public function testGetFileIdForStreamWithWritableStream(): void { $stream = $this->bucket->openUploadStream('filename', ['_id' => 1]); @@ -490,13 +492,13 @@ public function testGetFileIdForStreamWithWritableStream() /** * @dataProvider provideInvalidGridFSStreamValues */ - public function testGetFileIdForStreamShouldRequireGridFSStreamResource($stream) + public function testGetFileIdForStreamShouldRequireGridFSStreamResource($stream): void { $this->expectException(InvalidArgumentException::class); $this->bucket->getFileIdForStream($stream); } - public function testGetFilesCollection() + public function testGetFilesCollection(): void { $filesCollection = $this->bucket->getFilesCollection(); @@ -507,7 +509,7 @@ public function testGetFilesCollection() /** * @dataProvider provideInputDataAndExpectedChunks */ - public function testOpenDownloadStream($input) + public function testOpenDownloadStream($input): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); @@ -517,7 +519,7 @@ public function testOpenDownloadStream($input) /** * @dataProvider provideInputDataAndExpectedChunks */ - public function testOpenDownloadStreamAndMultipleReadOperations($input) + public function testOpenDownloadStreamAndMultipleReadOperations($input): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream($input)); $stream = $this->bucket->openDownloadStream($id); @@ -535,19 +537,19 @@ public function testOpenDownloadStreamAndMultipleReadOperations($input) $this->assertEquals($input, $buffer); } - public function testOpenDownloadStreamShouldRequireFileToExist() + public function testOpenDownloadStreamShouldRequireFileToExist(): void { $this->expectException(FileNotFoundException::class); $this->bucket->openDownloadStream('nonexistent-id'); } - public function testOpenDownloadStreamByNameShouldRequireFilenameToExist() + public function testOpenDownloadStreamByNameShouldRequireFilenameToExist(): void { $this->expectException(FileNotFoundException::class); $this->bucket->openDownloadStream('nonexistent-filename'); } - public function testOpenDownloadStreamByName() + public function testOpenDownloadStreamByName(): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo')); $this->bucket->uploadFromStream('filename', $this->createStream('bar')); @@ -565,7 +567,7 @@ public function testOpenDownloadStreamByName() /** * @dataProvider provideNonexistentFilenameAndRevision */ - public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision) + public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo')); $this->bucket->uploadFromStream('filename', $this->createStream('bar')); @@ -574,7 +576,7 @@ public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToEx $this->bucket->openDownloadStream($filename, ['revision' => $revision]); } - public function testOpenUploadStream() + public function testOpenUploadStream(): void { $stream = $this->bucket->openUploadStream('filename'); @@ -587,7 +589,7 @@ public function testOpenUploadStream() /** * @dataProvider provideInputDataAndExpectedChunks */ - public function testOpenUploadStreamAndMultipleWriteOperations($input) + public function testOpenUploadStreamAndMultipleWriteOperations($input): void { $stream = $this->bucket->openUploadStream('filename'); $offset = 0; @@ -604,7 +606,7 @@ public function testOpenUploadStreamAndMultipleWriteOperations($input) $this->assertStreamContents($input, $this->bucket->openDownloadStreamByName('filename')); } - public function testRename() + public function testRename(): void { $id = $this->bucket->uploadFromStream('a', $this->createStream('foo')); $this->bucket->rename($id, 'b'); @@ -618,7 +620,7 @@ public function testRename() $this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('b')); } - public function testRenameShouldNotRequireFileToBeModified() + public function testRenameShouldNotRequireFileToBeModified(): void { $id = $this->bucket->uploadFromStream('a', $this->createStream('foo')); $this->bucket->rename($id, 'a'); @@ -632,13 +634,13 @@ public function testRenameShouldNotRequireFileToBeModified() $this->assertStreamContents('foo', $this->bucket->openDownloadStreamByName('a')); } - public function testRenameShouldRequireFileToExist() + public function testRenameShouldRequireFileToExist(): void { $this->expectException(FileNotFoundException::class); $this->bucket->rename('nonexistent-id', 'b'); } - public function testUploadFromStream() + public function testUploadFromStream(): void { $options = [ '_id' => 'custom-id', @@ -660,13 +662,13 @@ public function testUploadFromStream() /** * @dataProvider provideInvalidStreamValues */ - public function testUploadFromStreamShouldRequireSourceStream($source) + public function testUploadFromStreamShouldRequireSourceStream($source): void { $this->expectException(InvalidArgumentException::class); $this->bucket->uploadFromStream('filename', $source); } - public function testUploadingAnEmptyFile() + public function testUploadingAnEmptyFile(): void { $id = $this->bucket->uploadFromStream('filename', $this->createStream('')); $destination = $this->createStream(); @@ -695,17 +697,17 @@ public function testUploadingAnEmptyFile() $this->assertSameDocument($expected, $fileDocument); } - public function testUploadingFirstFileCreatesIndexes() + public function testUploadingFirstFileCreatesIndexes(): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo')); $this->assertIndexExists($this->filesCollection->getCollectionName(), 'filename_1_uploadDate_1'); - $this->assertIndexExists($this->chunksCollection->getCollectionName(), 'files_id_1_n_1', function (IndexInfo $info) { + $this->assertIndexExists($this->chunksCollection->getCollectionName(), 'files_id_1_n_1', function (IndexInfo $info): void { $this->assertTrue($info->isUnique()); }); } - public function testExistingIndexIsReused() + public function testExistingIndexIsReused(): void { $this->filesCollection->createIndex(['filename' => 1.0, 'uploadDate' => 1], ['name' => 'test']); $this->chunksCollection->createIndex(['files_id' => 1.0, 'n' => 1], ['name' => 'test', 'unique' => true]); @@ -716,7 +718,7 @@ public function testExistingIndexIsReused() $this->assertIndexNotExists($this->chunksCollection->getCollectionName(), 'files_id_1_n_1'); } - public function testDownloadToStreamFails() + public function testDownloadToStreamFails(): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo'), ['_id' => ['foo' => 'bar']]); @@ -725,7 +727,7 @@ public function testDownloadToStreamFails() $this->bucket->downloadToStream(['foo' => 'bar'], fopen('php://temp', 'r')); } - public function testDownloadToStreamByNameFails() + public function testDownloadToStreamByNameFails(): void { $this->bucket->uploadFromStream('filename', $this->createStream('foo')); @@ -734,7 +736,7 @@ public function testDownloadToStreamByNameFails() $this->bucket->downloadToStreamByName('filename', fopen('php://temp', 'r')); } - public function testUploadFromStreamFails() + public function testUploadFromStreamFails(): void { if (PHP_VERSION_ID < 70400) { $this->markTestSkipped('Test only works on PHP 7.4 and newer'); @@ -748,7 +750,7 @@ public function testUploadFromStreamFails() $this->bucket->uploadFromStream('filename', $source); } - public function testDanglingOpenWritableStream() + public function testDanglingOpenWritableStream(): void { if (! strncasecmp(PHP_OS, 'WIN', 3)) { $this->markTestSkipped('Test does not apply to Windows'); @@ -777,7 +779,7 @@ public function testDanglingOpenWritableStream() * * @param string $collectionName */ - private function assertCollectionDoesNotExist($collectionName) + private function assertCollectionDoesNotExist(string $collectionName): void { $operation = new ListCollections($this->getDatabaseName()); $collections = $operation->execute($this->getPrimaryServer()); @@ -806,7 +808,7 @@ private function assertCollectionDoesNotExist($collectionName) * @param string $indexName * @param callable $callback */ - private function assertIndexExists($collectionName, $indexName, $callback = null) + private function assertIndexExists(string $collectionName, string $indexName, ?callable $callback = null): void { if ($callback !== null && ! is_callable($callback)) { throw new InvalidArgumentException('$callback is not a callable'); @@ -837,7 +839,7 @@ private function assertIndexExists($collectionName, $indexName, $callback = null * @param string $collectionName * @param string $indexName */ - private function assertIndexNotExists($collectionName, $indexName) + private function assertIndexNotExists(string $collectionName, string $indexName): void { $operation = new ListIndexes($this->getDatabaseName(), $collectionName); $indexes = $operation->execute($this->getPrimaryServer()); @@ -859,7 +861,7 @@ private function assertIndexNotExists($collectionName, $indexName) * * @return array */ - private function getInvalidStreamValues() + private function getInvalidStreamValues(): array { return [null, 123, 'foo', [], hash_init('md5')]; } diff --git a/tests/GridFS/FunctionalTestCase.php b/tests/GridFS/FunctionalTestCase.php index 58f2d83a9..5c2b8f45e 100644 --- a/tests/GridFS/FunctionalTestCase.php +++ b/tests/GridFS/FunctionalTestCase.php @@ -5,6 +5,7 @@ use MongoDB\Collection; use MongoDB\GridFS\Bucket; use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase; + use function fopen; use function fwrite; use function get_resource_type; @@ -25,7 +26,7 @@ abstract class FunctionalTestCase extends BaseFunctionalTestCase /** @var Collection */ protected $filesCollection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -44,7 +45,7 @@ public function setUp() : void * @param string $expectedContents * @param resource $stream */ - protected function assertStreamContents($expectedContents, $stream) + protected function assertStreamContents(string $expectedContents, $stream): void { $this->assertIsResource($stream); $this->assertSame('stream', get_resource_type($stream)); @@ -57,7 +58,7 @@ protected function assertStreamContents($expectedContents, $stream) * @param string $data * @return resource */ - protected function createStream($data = '') + protected function createStream(string $data = '') { $stream = fopen('php://temp', 'w+b'); fwrite($stream, $data); diff --git a/tests/GridFS/ReadableStreamFunctionalTest.php b/tests/GridFS/ReadableStreamFunctionalTest.php index 54789feca..42c9ddae1 100644 --- a/tests/GridFS/ReadableStreamFunctionalTest.php +++ b/tests/GridFS/ReadableStreamFunctionalTest.php @@ -8,6 +8,7 @@ use MongoDB\GridFS\Exception\CorruptFileException; use MongoDB\GridFS\ReadableStream; use MongoDB\Tests\CommandObserver; + use function array_filter; /** @@ -18,7 +19,7 @@ class ReadableStreamFunctionalTest extends FunctionalTestCase /** @var CollectionWrapper */ private $collectionWrapper; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -43,7 +44,7 @@ public function setUp() : void ]); } - public function testGetFile() + public function testGetFile(): void { $fileDocument = (object) ['_id' => null, 'chunkSize' => 1, 'length' => 0]; $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -53,7 +54,7 @@ public function testGetFile() /** * @dataProvider provideInvalidConstructorFileDocuments */ - public function testConstructorFileDocumentChecks($file) + public function testConstructorFileDocumentChecks($file): void { $this->expectException(CorruptFileException::class); new ReadableStream($this->collectionWrapper, $file); @@ -81,7 +82,7 @@ public function provideInvalidConstructorFileDocuments() /** * @dataProvider provideFileIdAndExpectedBytes */ - public function testReadBytes($fileId, $length, $expectedBytes) + public function testReadBytes($fileId, $length, $expectedBytes): void { $fileDocument = $this->collectionWrapper->findFileById($fileId); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -128,7 +129,7 @@ function (array $args) { /** * @dataProvider provideFilteredFileIdAndExpectedBytes */ - public function testReadBytesCalledMultipleTimes($fileId, $length, $expectedBytes) + public function testReadBytesCalledMultipleTimes($fileId, $length, $expectedBytes): void { $fileDocument = $this->collectionWrapper->findFileById($fileId); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -138,7 +139,7 @@ public function testReadBytesCalledMultipleTimes($fileId, $length, $expectedByte } } - public function testReadBytesWithMissingChunk() + public function testReadBytesWithMissingChunk(): void { $this->chunksCollection->deleteOne(['files_id' => 'length-10', 'n' => 2]); @@ -150,7 +151,7 @@ public function testReadBytesWithMissingChunk() $stream->readBytes(10); } - public function testReadBytesWithUnexpectedChunkIndex() + public function testReadBytesWithUnexpectedChunkIndex(): void { $this->chunksCollection->deleteOne(['files_id' => 'length-10', 'n' => 1]); @@ -162,7 +163,7 @@ public function testReadBytesWithUnexpectedChunkIndex() $stream->readBytes(10); } - public function testReadBytesWithUnexpectedChunkSize() + public function testReadBytesWithUnexpectedChunkSize(): void { $this->chunksCollection->updateOne( ['files_id' => 'length-10', 'n' => 2], @@ -177,7 +178,7 @@ public function testReadBytesWithUnexpectedChunkSize() $stream->readBytes(10); } - public function testReadBytesWithNegativeLength() + public function testReadBytesWithNegativeLength(): void { $fileDocument = $this->collectionWrapper->findFileById('length-0'); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -186,7 +187,7 @@ public function testReadBytesWithNegativeLength() $stream->readBytes(-1); } - public function testSeekBeforeReading() + public function testSeekBeforeReading(): void { $fileDocument = $this->collectionWrapper->findFileById('length-10'); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -195,7 +196,7 @@ public function testSeekBeforeReading() $this->assertSame('ij', $stream->readBytes(2)); } - public function testSeekOutOfRange() + public function testSeekOutOfRange(): void { $fileDocument = $this->collectionWrapper->findFileById('length-10'); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -208,7 +209,7 @@ public function testSeekOutOfRange() /** * @dataProvider providePreviousChunkSeekOffsetAndBytes */ - public function testSeekPreviousChunk($offset, $length, $expectedBytes) + public function testSeekPreviousChunk($offset, $length, $expectedBytes): void { $fileDocument = $this->collectionWrapper->findFileById('length-10'); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -219,11 +220,11 @@ public function testSeekPreviousChunk($offset, $length, $expectedBytes) $commands = []; (new CommandObserver())->observe( - function () use ($stream, $offset, $length, $expectedBytes) { + function () use ($stream, $offset, $length, $expectedBytes): void { $stream->seek($offset); $this->assertSame($expectedBytes, $stream->readBytes($length)); }, - function (array $event) use (&$commands) { + function (array $event) use (&$commands): void { $commands[] = $event['started']->getCommandName(); } ); @@ -244,7 +245,7 @@ public function providePreviousChunkSeekOffsetAndBytes() /** * @dataProvider provideSameChunkSeekOffsetAndBytes */ - public function testSeekSameChunk($offset, $length, $expectedBytes) + public function testSeekSameChunk($offset, $length, $expectedBytes): void { $fileDocument = $this->collectionWrapper->findFileById('length-10'); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -255,11 +256,11 @@ public function testSeekSameChunk($offset, $length, $expectedBytes) $commands = []; (new CommandObserver())->observe( - function () use ($stream, $offset, $length, $expectedBytes) { + function () use ($stream, $offset, $length, $expectedBytes): void { $stream->seek($offset); $this->assertSame($expectedBytes, $stream->readBytes($length)); }, - function (array $event) use (&$commands) { + function (array $event) use (&$commands): void { $commands[] = $event['started']->getCommandName(); } ); @@ -278,7 +279,7 @@ public function provideSameChunkSeekOffsetAndBytes() /** * @dataProvider provideSubsequentChunkSeekOffsetAndBytes */ - public function testSeekSubsequentChunk($offset, $length, $expectedBytes) + public function testSeekSubsequentChunk($offset, $length, $expectedBytes): void { $fileDocument = $this->collectionWrapper->findFileById('length-10'); $stream = new ReadableStream($this->collectionWrapper, $fileDocument); @@ -289,11 +290,11 @@ public function testSeekSubsequentChunk($offset, $length, $expectedBytes) $commands = []; (new CommandObserver())->observe( - function () use ($stream, $offset, $length, $expectedBytes) { + function () use ($stream, $offset, $length, $expectedBytes): void { $stream->seek($offset); $this->assertSame($expectedBytes, $stream->readBytes($length)); }, - function (array $event) use (&$commands) { + function (array $event) use (&$commands): void { $commands[] = $event['started']->getCommandName(); } ); diff --git a/tests/GridFS/StreamWrapperFunctionalTest.php b/tests/GridFS/StreamWrapperFunctionalTest.php index 8b54b2fd6..792338d36 100644 --- a/tests/GridFS/StreamWrapperFunctionalTest.php +++ b/tests/GridFS/StreamWrapperFunctionalTest.php @@ -4,12 +4,14 @@ use MongoDB\BSON\Binary; use MongoDB\BSON\UTCDateTime; + use function fclose; use function feof; use function fread; use function fseek; use function fstat; use function fwrite; + use const SEEK_CUR; use const SEEK_END; use const SEEK_SET; @@ -19,7 +21,7 @@ */ class StreamWrapperFunctionalTest extends FunctionalTestCase { - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -34,14 +36,14 @@ public function setUp() : void ]); } - public function testReadableStreamClose() + public function testReadableStreamClose(): void { $stream = $this->bucket->openDownloadStream('length-10'); $this->assertTrue(fclose($stream)); } - public function testReadableStreamEof() + public function testReadableStreamEof(): void { $stream = $this->bucket->openDownloadStream('length-10'); @@ -50,7 +52,7 @@ public function testReadableStreamEof() $this->assertTrue(feof($stream)); } - public function testReadableStreamRead() + public function testReadableStreamRead(): void { $stream = $this->bucket->openDownloadStream('length-10'); @@ -59,7 +61,7 @@ public function testReadableStreamRead() $this->assertSame('', fread($stream, 3)); } - public function testReadableStreamSeek() + public function testReadableStreamSeek(): void { $stream = $this->bucket->openDownloadStream('length-10'); @@ -85,7 +87,7 @@ public function testReadableStreamSeek() $this->assertSame(-1, fseek($stream, 1, SEEK_END)); } - public function testReadableStreamStat() + public function testReadableStreamStat(): void { $stream = $this->bucket->openDownloadStream('length-10'); @@ -102,14 +104,14 @@ public function testReadableStreamStat() $this->assertSame(4, $stat['blksize']); } - public function testReadableStreamWrite() + public function testReadableStreamWrite(): void { $stream = $this->bucket->openDownloadStream('length-10'); $this->assertSame(0, fwrite($stream, 'foobar')); } - public function testWritableStreamClose() + public function testWritableStreamClose(): void { $stream = $this->bucket->openUploadStream('filename'); @@ -119,7 +121,7 @@ public function testWritableStreamClose() $this->assertStreamContents('foobar', $this->bucket->openDownloadStreamByName('filename')); } - public function testWritableStreamEof() + public function testWritableStreamEof(): void { $stream = $this->bucket->openUploadStream('filename'); @@ -128,7 +130,7 @@ public function testWritableStreamEof() $this->assertFalse(feof($stream)); } - public function testWritableStreamRead() + public function testWritableStreamRead(): void { $stream = $this->bucket->openUploadStream('filename'); @@ -137,7 +139,7 @@ public function testWritableStreamRead() $this->assertSame('', fread($stream, 8192)); } - public function testWritableStreamSeek() + public function testWritableStreamSeek(): void { $stream = $this->bucket->openUploadStream('filename'); @@ -156,7 +158,7 @@ public function testWritableStreamSeek() $this->assertSame(-1, fseek($stream, 1, SEEK_END)); } - public function testWritableStreamStatBeforeSaving() + public function testWritableStreamStatBeforeSaving(): void { $stream = $this->bucket->openUploadStream('filename', ['chunkSizeBytes' => 1024]); @@ -179,7 +181,7 @@ public function testWritableStreamStatBeforeSaving() $this->assertSame(6, $stat['size']); } - public function testWritableStreamStatAfterSaving() + public function testWritableStreamStatAfterSaving(): void { $stream = $this->bucket->openDownloadStream('length-10'); @@ -196,7 +198,7 @@ public function testWritableStreamStatAfterSaving() $this->assertSame(4, $stat['blksize']); } - public function testWritableStreamWrite() + public function testWritableStreamWrite(): void { $stream = $this->bucket->openUploadStream('filename'); diff --git a/tests/GridFS/UnusableStream.php b/tests/GridFS/UnusableStream.php index f7c7970ce..328d7b3af 100644 --- a/tests/GridFS/UnusableStream.php +++ b/tests/GridFS/UnusableStream.php @@ -6,12 +6,13 @@ use function stream_get_wrappers; use function stream_wrapper_register; use function stream_wrapper_unregister; + use const SEEK_SET; use const STREAM_IS_URL; final class UnusableStream { - public static function register($protocol = 'unusable') + public static function register($protocol = 'unusable'): void { if (in_array($protocol, stream_get_wrappers())) { stream_wrapper_unregister($protocol); @@ -20,7 +21,7 @@ public static function register($protocol = 'unusable') stream_wrapper_register($protocol, static::class, STREAM_IS_URL); } - public function stream_close() + public function stream_close(): void { } diff --git a/tests/GridFS/WritableStreamFunctionalTest.php b/tests/GridFS/WritableStreamFunctionalTest.php index 1ffd119b3..8a550bffc 100644 --- a/tests/GridFS/WritableStreamFunctionalTest.php +++ b/tests/GridFS/WritableStreamFunctionalTest.php @@ -5,6 +5,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\CollectionWrapper; use MongoDB\GridFS\WritableStream; + use function str_repeat; /** @@ -15,7 +16,7 @@ class WritableStreamFunctionalTest extends FunctionalTestCase /** @var CollectionWrapper */ private $collectionWrapper; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -25,7 +26,7 @@ public function setUp() : void /** * @doesNotPerformAssertions */ - public function testValidConstructorOptions() + public function testValidConstructorOptions(): void { new WritableStream($this->collectionWrapper, 'filename', [ '_id' => 'custom-id', @@ -37,7 +38,7 @@ public function testValidConstructorOptions() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new WritableStream($this->collectionWrapper, 'filename', $options); @@ -62,14 +63,14 @@ public function provideInvalidConstructorOptions() return $options; } - public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive() + public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected "chunkSizeBytes" option to be >= 1, 0 given'); new WritableStream($this->collectionWrapper, 'filename', ['chunkSizeBytes' => 0]); } - public function testWriteBytesAlwaysUpdatesFileSize() + public function testWriteBytesAlwaysUpdatesFileSize(): void { $stream = new WritableStream($this->collectionWrapper, 'filename', ['chunkSizeBytes' => 1024]); @@ -88,7 +89,7 @@ public function testWriteBytesAlwaysUpdatesFileSize() /** * @dataProvider provideInputDataAndExpectedMD5 */ - public function testWriteBytesCalculatesMD5($input, $expectedMD5) + public function testWriteBytesCalculatesMD5($input, $expectedMD5): void { $stream = new WritableStream($this->collectionWrapper, 'filename'); $stream->writeBytes($input); diff --git a/tests/Model/BSONArrayTest.php b/tests/Model/BSONArrayTest.php index 8774d223b..9f420bed9 100644 --- a/tests/Model/BSONArrayTest.php +++ b/tests/Model/BSONArrayTest.php @@ -8,11 +8,12 @@ use MongoDB\Tests\TestCase; use ReflectionClass; use stdClass; + use function json_encode; class BSONArrayTest extends TestCase { - public function testBsonSerializeReindexesKeys() + public function testBsonSerializeReindexesKeys(): void { $data = [0 => 'foo', 2 => 'bar']; @@ -21,7 +22,7 @@ public function testBsonSerializeReindexesKeys() $this->assertSame(['foo', 'bar'], $array->bsonSerialize()); } - public function testClone() + public function testClone(): void { $array = new BSONArray([ [ @@ -46,7 +47,7 @@ public function testClone() $this->assertNotSame($array[1][2][1], $arrayClone[1][2][1]); } - public function testCloneRespectsUncloneableObjects() + public function testCloneRespectsUncloneableObjects(): void { $this->assertFalse((new ReflectionClass(UncloneableObject::class))->isCloneable()); @@ -62,7 +63,7 @@ public function testCloneRespectsUncloneableObjects() $this->assertSame($array[1][0], $arrayClone[1][0]); } - public function testCloneSupportsBSONTypes() + public function testCloneSupportsBSONTypes(): void { /* Note: this test does not check that the BSON type itself is cloned, * as that is not yet supported in the driver (see: PHPC-1230). */ @@ -76,7 +77,7 @@ public function testCloneSupportsBSONTypes() $this->assertNotSame($array[1], $arrayClone[1]); } - public function testJsonSerialize() + public function testJsonSerialize(): void { $document = new BSONArray([ 'foo', @@ -90,7 +91,7 @@ public function testJsonSerialize() $this->assertSame($expectedJson, json_encode($document)); } - public function testJsonSerializeReindexesKeys() + public function testJsonSerializeReindexesKeys(): void { $data = [0 => 'foo', 2 => 'bar']; @@ -99,7 +100,7 @@ public function testJsonSerializeReindexesKeys() $this->assertSame(['foo', 'bar'], $array->jsonSerialize()); } - public function testSetState() + public function testSetState(): void { $data = ['foo', 'bar']; diff --git a/tests/Model/BSONDocumentTest.php b/tests/Model/BSONDocumentTest.php index ad095e31f..bd0009dcf 100644 --- a/tests/Model/BSONDocumentTest.php +++ b/tests/Model/BSONDocumentTest.php @@ -9,18 +9,19 @@ use MongoDB\Tests\TestCase; use ReflectionClass; use stdClass; + use function json_encode; class BSONDocumentTest extends TestCase { - public function testConstructorDefaultsToPropertyAccess() + public function testConstructorDefaultsToPropertyAccess(): void { $document = new BSONDocument(['foo' => 'bar']); $this->assertEquals(ArrayObject::ARRAY_AS_PROPS, $document->getFlags()); $this->assertSame('bar', $document->foo); } - public function testBsonSerializeCastsToObject() + public function testBsonSerializeCastsToObject(): void { $data = [0 => 'foo', 2 => 'bar']; @@ -29,7 +30,7 @@ public function testBsonSerializeCastsToObject() $this->assertEquals((object) [0 => 'foo', 2 => 'bar'], $document->bsonSerialize()); } - public function testClone() + public function testClone(): void { $document = new BSONDocument([ 'a' => [ @@ -54,7 +55,7 @@ public function testClone() $this->assertNotSame($document['b']['c'][1], $documentClone['b']['c'][1]); } - public function testCloneRespectsUncloneableObjects() + public function testCloneRespectsUncloneableObjects(): void { $this->assertFalse((new ReflectionClass(UncloneableObject::class))->isCloneable()); @@ -70,7 +71,7 @@ public function testCloneRespectsUncloneableObjects() $this->assertSame($document['b']['a'], $documentClone['b']['a']); } - public function testCloneSupportsBSONTypes() + public function testCloneSupportsBSONTypes(): void { /* Note: this test does not check that the BSON type itself is cloned, * as that is not yet supported in the driver (see: PHPC-1230). */ @@ -84,7 +85,7 @@ public function testCloneSupportsBSONTypes() $this->assertNotSame($document['b'], $documentClone['b']); } - public function testJsonSerialize() + public function testJsonSerialize(): void { $document = new BSONDocument([ 'foo' => 'bar', @@ -98,7 +99,7 @@ public function testJsonSerialize() $this->assertSame($expectedJson, json_encode($document)); } - public function testJsonSerializeCastsToObject() + public function testJsonSerializeCastsToObject(): void { $data = [0 => 'foo', 2 => 'bar']; @@ -107,7 +108,7 @@ public function testJsonSerializeCastsToObject() $this->assertEquals((object) [0 => 'foo', 2 => 'bar'], $document->jsonSerialize()); } - public function testSetState() + public function testSetState(): void { $data = ['foo' => 'bar']; diff --git a/tests/Model/BSONIteratorTest.php b/tests/Model/BSONIteratorTest.php index c48ed393d..e20b9d2cb 100644 --- a/tests/Model/BSONIteratorTest.php +++ b/tests/Model/BSONIteratorTest.php @@ -5,6 +5,7 @@ use MongoDB\Exception\UnexpectedValueException; use MongoDB\Model\BSONIterator; use MongoDB\Tests\TestCase; + use function array_map; use function implode; use function iterator_to_array; @@ -16,7 +17,7 @@ class BSONIteratorTest extends TestCase /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testValidValues(array $typeMap = null, $binaryString, array $expectedDocuments) + public function testValidValues(?array $typeMap = null, $binaryString, array $expectedDocuments): void { $bsonIt = new BSONIterator($binaryString, ['typeMap' => $typeMap]); @@ -87,7 +88,7 @@ public function provideTypeMapOptionsAndExpectedDocuments() ]; } - public function testCannotReadLengthFromFirstDocument() + public function testCannotReadLengthFromFirstDocument(): void { $binaryString = substr(fromPHP([]), 0, 3); @@ -98,7 +99,7 @@ public function testCannotReadLengthFromFirstDocument() $bsonIt->rewind(); } - public function testCannotReadLengthFromSubsequentDocument() + public function testCannotReadLengthFromSubsequentDocument(): void { $binaryString = fromPHP([]) . substr(fromPHP([]), 0, 3); @@ -110,7 +111,7 @@ public function testCannotReadLengthFromSubsequentDocument() $bsonIt->next(); } - public function testCannotReadFirstDocument() + public function testCannotReadFirstDocument(): void { $binaryString = substr(fromPHP([]), 0, 4); @@ -121,7 +122,7 @@ public function testCannotReadFirstDocument() $bsonIt->rewind(); } - public function testCannotReadSecondDocument() + public function testCannotReadSecondDocument(): void { $binaryString = fromPHP([]) . substr(fromPHP([]), 0, 4); diff --git a/tests/Model/CachingIteratorTest.php b/tests/Model/CachingIteratorTest.php index 0306d8491..e3057ca43 100644 --- a/tests/Model/CachingIteratorTest.php +++ b/tests/Model/CachingIteratorTest.php @@ -7,11 +7,12 @@ use MongoDB\Model\CachingIterator; use MongoDB\Tests\TestCase; use Throwable; + use function iterator_to_array; class CachingIteratorTest extends TestCase { - public function testTraversingGeneratorConsumesIt() + public function testTraversingGeneratorConsumesIt(): void { $iterator = $this->getTraversable([1, 2, 3]); $this->assertSame([1, 2, 3], iterator_to_array($iterator)); @@ -21,7 +22,7 @@ public function testTraversingGeneratorConsumesIt() iterator_to_array($iterator); } - public function testConstructorRewinds() + public function testConstructorRewinds(): void { $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); @@ -30,7 +31,7 @@ public function testConstructorRewinds() $this->assertSame(1, $iterator->current()); } - public function testIteration() + public function testIteration(): void { $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); @@ -45,7 +46,7 @@ public function testIteration() $this->assertFalse($iterator->valid()); } - public function testIterationWithEmptySet() + public function testIterationWithEmptySet(): void { $iterator = new CachingIterator($this->getTraversable([])); @@ -53,7 +54,7 @@ public function testIterationWithEmptySet() $this->assertFalse($iterator->valid()); } - public function testPartialIterationDoesNotExhaust() + public function testPartialIterationDoesNotExhaust(): void { $traversable = $this->getTraversable([1, 2, new Exception()]); $iterator = new CachingIterator($traversable); @@ -73,7 +74,7 @@ public function testPartialIterationDoesNotExhaust() $this->assertTrue($iterator->valid()); } - public function testRewindAfterPartialIteration() + public function testRewindAfterPartialIteration(): void { $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); @@ -86,13 +87,13 @@ public function testRewindAfterPartialIteration() $this->assertSame([1, 2, 3], iterator_to_array($iterator)); } - public function testCount() + public function testCount(): void { $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); $this->assertCount(3, $iterator); } - public function testCountAfterPartialIteration() + public function testCountAfterPartialIteration(): void { $iterator = new CachingIterator($this->getTraversable([1, 2, 3])); @@ -105,7 +106,7 @@ public function testCountAfterPartialIteration() $this->assertCount(3, $iterator); } - public function testCountWithEmptySet() + public function testCountWithEmptySet(): void { $iterator = new CachingIterator($this->getTraversable([])); $this->assertCount(0, $iterator); @@ -115,7 +116,7 @@ public function testCountWithEmptySet() * This protects against iterators that return valid keys on invalid * positions, which was the case in ext-mongodb until PHPC-1748 was fixed. */ - public function testWithWrongIterator() + public function testWithWrongIterator(): void { $nestedIterator = new class implements Iterator { /** @var int */ @@ -126,7 +127,7 @@ public function current() return $this->i; } - public function next() + public function next(): void { $this->i++; } @@ -141,7 +142,7 @@ public function valid() return $this->i == 0; } - public function rewind() + public function rewind(): void { $this->i = 0; } diff --git a/tests/Model/ChangeStreamIteratorTest.php b/tests/Model/ChangeStreamIteratorTest.php index 5e13b3868..af3f0bdf6 100644 --- a/tests/Model/ChangeStreamIteratorTest.php +++ b/tests/Model/ChangeStreamIteratorTest.php @@ -11,6 +11,7 @@ use MongoDB\Operation\Find; use MongoDB\Tests\CommandObserver; use MongoDB\Tests\FunctionalTestCase; + use function array_merge; use function sprintf; @@ -19,7 +20,7 @@ class ChangeStreamIteratorTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -35,7 +36,7 @@ public function setUp() : void /** * @dataProvider provideInvalidIntegerValues */ - public function testFirstBatchArgumentTypeCheck($firstBatchSize) + public function testFirstBatchArgumentTypeCheck($firstBatchSize): void { $this->expectException(InvalidArgumentException::class); new ChangeStreamIterator($this->collection->find(), $firstBatchSize, null, null); @@ -46,7 +47,7 @@ public function provideInvalidIntegerValues() return $this->wrapValuesForDataProvider($this->getInvalidIntegerValues()); } - public function testInitialResumeToken() + public function testInitialResumeToken(): void { $iterator = new ChangeStreamIterator($this->collection->find(), 0, null, null); $this->assertNull($iterator->getResumeToken()); @@ -61,7 +62,7 @@ public function testInitialResumeToken() /** * @dataProvider provideInvalidDocumentValues */ - public function testInitialResumeTokenArgumentTypeCheck($initialResumeToken) + public function testInitialResumeTokenArgumentTypeCheck($initialResumeToken): void { $this->expectException(InvalidArgumentException::class); new ChangeStreamIterator($this->collection->find(), 0, $initialResumeToken, null); @@ -70,7 +71,7 @@ public function testInitialResumeTokenArgumentTypeCheck($initialResumeToken) /** * @dataProvider provideInvalidObjectValues */ - public function testPostBatchResumeTokenArgumentTypeCheck($postBatchResumeToken) + public function testPostBatchResumeTokenArgumentTypeCheck($postBatchResumeToken): void { $this->expectException(InvalidArgumentException::class); new ChangeStreamIterator($this->collection->find(), 0, null, $postBatchResumeToken); @@ -81,7 +82,7 @@ public function provideInvalidObjectValues() return $this->wrapValuesForDataProvider(array_merge($this->getInvalidDocumentValues(), [[]])); } - public function testPostBatchResumeTokenIsReturnedForLastElementInFirstBatch() + public function testPostBatchResumeTokenIsReturnedForLastElementInFirstBatch(): void { $this->collection->insertOne(['_id' => ['resumeToken' => 1], 'x' => 1]); $this->collection->insertOne(['_id' => ['resumeToken' => 2], 'x' => 2]); @@ -90,7 +91,7 @@ public function testPostBatchResumeTokenIsReturnedForLastElementInFirstBatch() $cursor = $this->collection->find([], ['cursorType' => Find::TAILABLE]); $iterator = new ChangeStreamIterator($cursor, 2, null, $postBatchResumeToken); - $this->assertNoCommandExecuted(function () use ($iterator) { + $this->assertNoCommandExecuted(function () use ($iterator): void { $iterator->rewind(); }); $this->assertTrue($iterator->valid()); @@ -103,14 +104,14 @@ public function testPostBatchResumeTokenIsReturnedForLastElementInFirstBatch() $this->assertSameDocument(['_id' => ['resumeToken' => 2], 'x' => 2], $iterator->current()); } - public function testRewindIsNopWhenFirstBatchIsEmpty() + public function testRewindIsNopWhenFirstBatchIsEmpty(): void { $this->collection->insertOne(['_id' => ['resumeToken' => 1], 'x' => 1]); $cursor = $this->collection->find(['x' => ['$gt' => 1]], ['cursorType' => Find::TAILABLE]); $iterator = new ChangeStreamIterator($cursor, 0, null, null); - $this->assertNoCommandExecuted(function () use ($iterator) { + $this->assertNoCommandExecuted(function () use ($iterator): void { $iterator->rewind(); }); $this->assertFalse($iterator->valid()); @@ -125,14 +126,14 @@ public function testRewindIsNopWhenFirstBatchIsEmpty() $iterator->rewind(); } - public function testRewindAdvancesWhenFirstBatchIsNotEmpty() + public function testRewindAdvancesWhenFirstBatchIsNotEmpty(): void { $this->collection->insertOne(['_id' => ['resumeToken' => 1], 'x' => 1]); $cursor = $this->collection->find([], ['cursorType' => Find::TAILABLE]); $iterator = new ChangeStreamIterator($cursor, 1, null, null); - $this->assertNoCommandExecuted(function () use ($iterator) { + $this->assertNoCommandExecuted(function () use ($iterator): void { $iterator->rewind(); }); $this->assertTrue($iterator->valid()); @@ -148,13 +149,13 @@ public function testRewindAdvancesWhenFirstBatchIsNotEmpty() $iterator->rewind(); } - private function assertNoCommandExecuted(callable $callable) + private function assertNoCommandExecuted(callable $callable): void { $commands = []; (new CommandObserver())->observe( $callable, - function (array $event) use (&$commands) { + function (array $event) use (&$commands): void { $this->fail(sprintf('"%s" command was executed', $event['started']->getCommandName())); } ); diff --git a/tests/Model/CollectionInfoTest.php b/tests/Model/CollectionInfoTest.php index 4320e7df1..322c39586 100644 --- a/tests/Model/CollectionInfoTest.php +++ b/tests/Model/CollectionInfoTest.php @@ -8,13 +8,13 @@ class CollectionInfoTest extends TestCase { - public function testGetName() + public function testGetName(): void { $info = new CollectionInfo(['name' => 'foo']); $this->assertSame('foo', $info->getName()); } - public function testGetOptions() + public function testGetOptions(): void { $info = new CollectionInfo(['name' => 'foo']); $this->assertSame([], $info->getOptions()); @@ -23,7 +23,7 @@ public function testGetOptions() $this->assertSame(['capped' => true, 'size' => 1048576], $info->getOptions()); } - public function testCappedCollectionMethods() + public function testCappedCollectionMethods(): void { $info = new CollectionInfo(['name' => 'foo']); $this->assertFalse($info->isCapped()); @@ -41,7 +41,7 @@ public function testCappedCollectionMethods() $this->assertSame(1048576, $info->getCappedSize()); } - public function testDebugInfo() + public function testDebugInfo(): void { $expectedInfo = [ 'name' => 'foo', @@ -52,7 +52,7 @@ public function testDebugInfo() $this->assertSame($expectedInfo, $info->__debugInfo()); } - public function testImplementsArrayAccess() + public function testImplementsArrayAccess(): void { $info = new CollectionInfo(['name' => 'foo']); $this->assertInstanceOf('ArrayAccess', $info); @@ -60,7 +60,7 @@ public function testImplementsArrayAccess() $this->assertSame('foo', $info['name']); } - public function testOffsetSetCannotBeCalled() + public function testOffsetSetCannotBeCalled(): void { $info = new CollectionInfo(['name' => 'foo', 'options' => ['capped' => true, 'size' => 1048576]]); $this->expectException(BadMethodCallException::class); @@ -68,7 +68,7 @@ public function testOffsetSetCannotBeCalled() $info['options'] = ['capped' => false]; } - public function testOffsetUnsetCannotBeCalled() + public function testOffsetUnsetCannotBeCalled(): void { $info = new CollectionInfo(['name' => 'foo', 'options' => ['capped' => true, 'size' => 1048576]]); $this->expectException(BadMethodCallException::class); diff --git a/tests/Model/DatabaseInfoTest.php b/tests/Model/DatabaseInfoTest.php index 2c9819ee6..14e083a08 100644 --- a/tests/Model/DatabaseInfoTest.php +++ b/tests/Model/DatabaseInfoTest.php @@ -8,19 +8,19 @@ class DatabaseInfoTest extends TestCase { - public function testGetName() + public function testGetName(): void { $info = new DatabaseInfo(['name' => 'foo']); $this->assertSame('foo', $info->getName()); } - public function testGetSizeOnDisk() + public function testGetSizeOnDisk(): void { $info = new DatabaseInfo(['sizeOnDisk' => 1048576]); $this->assertSame(1048576, $info->getSizeOnDisk()); } - public function testIsEmpty() + public function testIsEmpty(): void { $info = new DatabaseInfo(['empty' => false]); $this->assertFalse($info->isEmpty()); @@ -29,7 +29,7 @@ public function testIsEmpty() $this->assertTrue($info->isEmpty()); } - public function testDebugInfo() + public function testDebugInfo(): void { $expectedInfo = [ 'name' => 'foo', @@ -41,7 +41,7 @@ public function testDebugInfo() $this->assertSame($expectedInfo, $info->__debugInfo()); } - public function testImplementsArrayAccess() + public function testImplementsArrayAccess(): void { $info = new DatabaseInfo(['name' => 'foo']); $this->assertInstanceOf('ArrayAccess', $info); @@ -49,7 +49,7 @@ public function testImplementsArrayAccess() $this->assertSame('foo', $info['name']); } - public function testOffsetSetCannotBeCalled() + public function testOffsetSetCannotBeCalled(): void { $info = new DatabaseInfo(['name' => 'foo', 'sizeOnDisk' => 1048576, 'empty' => false]); $this->expectException(BadMethodCallException::class); @@ -57,7 +57,7 @@ public function testOffsetSetCannotBeCalled() $info['empty'] = true; } - public function testOffsetUnsetCannotBeCalled() + public function testOffsetUnsetCannotBeCalled(): void { $info = new DatabaseInfo(['name' => 'foo', 'sizeOnDisk' => 1048576, 'empty' => false]); $this->expectException(BadMethodCallException::class); diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index d40a2573e..4eb5a4125 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -4,6 +4,7 @@ use MongoDB\Collection; use MongoDB\Tests\FunctionalTestCase; + use function version_compare; class IndexInfoFunctionalTest extends FunctionalTestCase @@ -11,7 +12,7 @@ class IndexInfoFunctionalTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -19,7 +20,7 @@ public function setUp() : void $this->collection->drop(); } - public function tearDown() : void + public function tearDown(): void { if ($this->hasFailed()) { return; @@ -30,7 +31,7 @@ public function tearDown() : void parent::tearDown(); } - public function testIs2dSphere() + public function testIs2dSphere(): void { $indexName = $this->collection->createIndex(['pos' => '2dsphere']); $result = $this->collection->listIndexes(); @@ -51,7 +52,7 @@ public function testIs2dSphere() * @group matrix-testing-exclude-server-5.0-driver-4.2 * @group matrix-testing-exclude-server-5.0-driver-4.4 */ - public function testIsGeoHaystack() + public function testIsGeoHaystack(): void { $this->skipIfGeoHaystackIndexIsNotSupported(); @@ -67,7 +68,7 @@ public function testIsGeoHaystack() $this->assertEquals(5, $index['bucketSize']); } - public function testIsText() + public function testIsText(): void { $indexName = $this->collection->createIndex(['x' => 'text']); $result = $this->collection->listIndexes(); diff --git a/tests/Model/IndexInfoTest.php b/tests/Model/IndexInfoTest.php index 33cfcda52..b4c482597 100644 --- a/tests/Model/IndexInfoTest.php +++ b/tests/Model/IndexInfoTest.php @@ -8,7 +8,7 @@ class IndexInfoTest extends TestCase { - public function testBasicIndex() + public function testBasicIndex(): void { $info = new IndexInfo([ 'v' => 1, @@ -29,7 +29,7 @@ public function testBasicIndex() $this->assertFalse($info->isUnique()); } - public function testSparseIndex() + public function testSparseIndex(): void { $info = new IndexInfo([ 'v' => 1, @@ -51,7 +51,7 @@ public function testSparseIndex() $this->assertFalse($info->isUnique()); } - public function testUniqueIndex() + public function testUniqueIndex(): void { $info = new IndexInfo([ 'v' => 1, @@ -73,7 +73,7 @@ public function testUniqueIndex() $this->assertTrue($info->isUnique()); } - public function testTtlIndex() + public function testTtlIndex(): void { $info = new IndexInfo([ 'v' => 1, @@ -97,7 +97,7 @@ public function testTtlIndex() $this->assertSame(100, $info['expireAfterSeconds']); } - public function testDebugInfo() + public function testDebugInfo(): void { $expectedInfo = [ 'v' => 1, @@ -110,7 +110,7 @@ public function testDebugInfo() $this->assertSame($expectedInfo, $info->__debugInfo()); } - public function testImplementsArrayAccess() + public function testImplementsArrayAccess(): void { $info = new IndexInfo([ 'v' => 1, @@ -124,7 +124,7 @@ public function testImplementsArrayAccess() $this->assertSame('x_1', $info['name']); } - public function testOffsetSetCannotBeCalled() + public function testOffsetSetCannotBeCalled(): void { $info = new IndexInfo([ 'v' => 1, @@ -138,7 +138,7 @@ public function testOffsetSetCannotBeCalled() $info['v'] = 2; } - public function testOffsetUnsetCannotBeCalled() + public function testOffsetUnsetCannotBeCalled(): void { $info = new IndexInfo([ 'v' => 1, @@ -152,7 +152,7 @@ public function testOffsetUnsetCannotBeCalled() unset($info['v']); } - public function testIs2dSphere() + public function testIs2dSphere(): void { $info = new IndexInfo([ 'v' => 2, @@ -173,7 +173,7 @@ public function testIs2dSphere() $this->assertFalse($info->isUnique()); } - public function testIsGeoHaystack() + public function testIsGeoHaystack(): void { $info = new IndexInfo([ 'v' => 2, @@ -194,7 +194,7 @@ public function testIsGeoHaystack() $this->assertFalse($info->isUnique()); } - public function testIsText() + public function testIsText(): void { $info = new IndexInfo([ 'v' => 2, diff --git a/tests/Model/IndexInputTest.php b/tests/Model/IndexInputTest.php index da6876169..673df1e5d 100644 --- a/tests/Model/IndexInputTest.php +++ b/tests/Model/IndexInputTest.php @@ -10,13 +10,13 @@ class IndexInputTest extends TestCase { - public function testConstructorShouldRequireKey() + public function testConstructorShouldRequireKey(): void { $this->expectException(InvalidArgumentException::class); new IndexInput([]); } - public function testConstructorShouldRequireKeyToBeArrayOrObject() + public function testConstructorShouldRequireKeyToBeArrayOrObject(): void { $this->expectException(InvalidArgumentException::class); new IndexInput(['key' => 'foo']); @@ -25,7 +25,7 @@ public function testConstructorShouldRequireKeyToBeArrayOrObject() /** * @dataProvider provideInvalidFieldOrderValues */ - public function testConstructorShouldRequireKeyFieldOrderToBeNumericOrString($order) + public function testConstructorShouldRequireKeyFieldOrderToBeNumericOrString($order): void { $this->expectException(InvalidArgumentException::class); new IndexInput(['key' => ['x' => $order]]); @@ -36,7 +36,7 @@ public function provideInvalidFieldOrderValues() return $this->wrapValuesForDataProvider([true, [], new stdClass()]); } - public function testConstructorShouldRequireNameToBeString() + public function testConstructorShouldRequireNameToBeString(): void { $this->expectException(InvalidArgumentException::class); new IndexInput(['key' => ['x' => 1], 'name' => 1]); @@ -45,7 +45,7 @@ public function testConstructorShouldRequireNameToBeString() /** * @dataProvider provideExpectedNameAndKey */ - public function testNameGeneration($expectedName, array $key) + public function testNameGeneration($expectedName, array $key): void { $this->assertSame($expectedName, (string) new IndexInput(['key' => $key])); } @@ -61,7 +61,7 @@ public function provideExpectedNameAndKey() ]; } - public function testBsonSerialization() + public function testBsonSerialization(): void { $expected = [ 'key' => ['x' => 1], diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php index 64e53f1b7..d6b75522a 100644 --- a/tests/Operation/AggregateFunctionalTest.php +++ b/tests/Operation/AggregateFunctionalTest.php @@ -11,16 +11,17 @@ use MongoDB\Operation\Aggregate; use MongoDB\Tests\CommandObserver; use stdClass; + use function current; use function iterator_to_array; use function version_compare; class AggregateFunctionalTest extends FunctionalTestCase { - public function testBatchSizeIsIgnoredIfPipelineIncludesOutStage() + public function testBatchSizeIsIgnoredIfPipelineIncludesOutStage(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( $this->getDatabaseName(), $this->getCollectionName(), @@ -30,7 +31,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertEquals(new stdClass(), $event['started']->getCommand()->cursor); } ); @@ -39,14 +40,14 @@ function (array $event) { $outCollection->drop(); } - public function testCurrentOpCommand() + public function testCurrentOpCommand(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('$currentOp is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( 'admin', null, @@ -55,16 +56,16 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertSame(1, $event['started']->getCommand()->aggregate); } ); } - public function testDefaultReadConcernIsOmitted() + public function testDefaultReadConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( $this->getDatabaseName(), $this->getCollectionName(), @@ -74,16 +75,16 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } ); } - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( $this->getDatabaseName(), $this->getCollectionName(), @@ -93,7 +94,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); @@ -102,7 +103,7 @@ function (array $event) { $outCollection->drop(); } - public function testEmptyPipelineReturnsAllDocuments() + public function testEmptyPipelineReturnsAllDocuments(): void { $this->createFixtures(3); @@ -118,21 +119,21 @@ public function testEmptyPipelineReturnsAllDocuments() $this->assertEquals($expectedDocuments, $results); } - public function testUnrecognizedPipelineState() + public function testUnrecognizedPipelineState(): void { $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [['$foo' => 1]]); $this->expectException(RuntimeException::class); $operation->execute($this->getPrimaryServer()); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( $this->getDatabaseName(), $this->getCollectionName(), @@ -142,7 +143,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -151,7 +152,7 @@ function (array $event) { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOption(array $typeMap = null, array $expectedDocuments) + public function testTypeMapOption(?array $typeMap = null, array $expectedDocuments): void { $this->createFixtures(3); @@ -166,7 +167,7 @@ public function testTypeMapOption(array $typeMap = null, array $expectedDocument /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOptionWithoutCursor(array $typeMap = null, array $expectedDocuments) + public function testTypeMapOptionWithoutCursor(?array $typeMap = null, array $expectedDocuments): void { if (version_compare($this->getServerVersion(), '3.6.0', '>=')) { $this->markTestSkipped('Aggregations with useCursor == false are not supported'); @@ -183,7 +184,7 @@ public function testTypeMapOptionWithoutCursor(array $typeMap = null, array $exp $this->assertEquals($expectedDocuments, iterator_to_array($results)); } - public function testExplainOption() + public function testExplainOption(): void { $this->createFixtures(3); @@ -201,7 +202,7 @@ public function testExplainOption() )); } - public function testExplainOptionWithWriteConcern() + public function testExplainOptionWithWriteConcern(): void { if (version_compare($this->getServerVersion(), '3.4.0', '<')) { $this->markTestSkipped('The writeConcern option is not supported'); @@ -213,7 +214,7 @@ public function testExplainOptionWithWriteConcern() $options = ['explain' => true, 'writeConcern' => new WriteConcern(1)]; (new CommandObserver())->observe( - function () use ($pipeline, $options) { + function () use ($pipeline, $options): void { $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), $pipeline, $options); $results = iterator_to_array($operation->execute($this->getPrimaryServer())); @@ -229,7 +230,7 @@ function () use ($pipeline, $options) { $this->assertObjectHasAttribute('stages', $result); } }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); @@ -237,14 +238,14 @@ function (array $event) { $this->assertCollectionCount($this->getCollectionName() . '.output', 0); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( $this->getDatabaseName(), $this->getCollectionName(), @@ -254,21 +255,21 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Aggregate( $this->getDatabaseName(), $this->getCollectionName(), @@ -278,7 +279,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); @@ -325,7 +326,7 @@ public function provideTypeMapOptionsAndExpectedDocuments() ]; } - public function testReadPreferenceWithinTransaction() + public function testReadPreferenceWithinTransaction(): void { $this->skipIfTransactionsAreNotSupported(); @@ -366,7 +367,7 @@ public function testReadPreferenceWithinTransaction() * @param integer $n * @param array $executeBulkWriteOptions */ - private function createFixtures($n, array $executeBulkWriteOptions = []) + private function createFixtures(int $n, array $executeBulkWriteOptions = []): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php index e165a7f7e..c7ecf0edb 100644 --- a/tests/Operation/AggregateTest.php +++ b/tests/Operation/AggregateTest.php @@ -7,7 +7,7 @@ class AggregateTest extends TestCase { - public function testConstructorPipelineArgumentMustBeAList() + public function testConstructorPipelineArgumentMustBeAList(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$pipeline is not a list (unexpected index: "1")'); @@ -17,7 +17,7 @@ public function testConstructorPipelineArgumentMustBeAList() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [['$match' => ['x' => 1]]], $options); @@ -94,7 +94,7 @@ public function provideInvalidConstructorOptions() return $options; } - public function testConstructorBatchSizeOptionRequiresUseCursor() + public function testConstructorBatchSizeOptionRequiresUseCursor(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('"batchSize" option should not be used if "useCursor" is false'); diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php index 5093ca2fd..ad0f28425 100644 --- a/tests/Operation/BulkWriteFunctionalTest.php +++ b/tests/Operation/BulkWriteFunctionalTest.php @@ -11,6 +11,7 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\BulkWrite; use MongoDB\Tests\CommandObserver; + use function version_compare; class BulkWriteFunctionalTest extends FunctionalTestCase @@ -18,14 +19,14 @@ class BulkWriteFunctionalTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName()); } - public function testInserts() + public function testInserts(): void { $ops = [ ['insertOne' => [['_id' => 1, 'x' => 11]]], @@ -56,7 +57,7 @@ public function testInserts() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testUpdates() + public function testUpdates(): void { $this->createFixtures(4); @@ -92,7 +93,7 @@ public function testUpdates() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testDeletes() + public function testDeletes(): void { $this->createFixtures(4); @@ -114,7 +115,7 @@ public function testDeletes() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testMixedOrderedOperations() + public function testMixedOrderedOperations(): void { $this->createFixtures(3); @@ -165,7 +166,7 @@ public function testUnacknowledgedWriteConcern() /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesDeletedCount(BulkWriteResult $result) + public function testUnacknowledgedWriteConcernAccessesDeletedCount(BulkWriteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -175,7 +176,7 @@ public function testUnacknowledgedWriteConcernAccessesDeletedCount(BulkWriteResu /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesInsertCount(BulkWriteResult $result) + public function testUnacknowledgedWriteConcernAccessesInsertCount(BulkWriteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -185,7 +186,7 @@ public function testUnacknowledgedWriteConcernAccessesInsertCount(BulkWriteResul /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesMatchedCount(BulkWriteResult $result) + public function testUnacknowledgedWriteConcernAccessesMatchedCount(BulkWriteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -195,7 +196,7 @@ public function testUnacknowledgedWriteConcernAccessesMatchedCount(BulkWriteResu /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesModifiedCount(BulkWriteResult $result) + public function testUnacknowledgedWriteConcernAccessesModifiedCount(BulkWriteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -205,7 +206,7 @@ public function testUnacknowledgedWriteConcernAccessesModifiedCount(BulkWriteRes /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesUpsertedCount(BulkWriteResult $result) + public function testUnacknowledgedWriteConcernAccessesUpsertedCount(BulkWriteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -215,21 +216,21 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedCount(BulkWriteRes /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesUpsertedIds(BulkWriteResult $result) + public function testUnacknowledgedWriteConcernAccessesUpsertedIds(BulkWriteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); $result->getUpsertedIds(); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new BulkWrite( $this->getDatabaseName(), $this->getCollectionName(), @@ -239,20 +240,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new BulkWrite( $this->getDatabaseName(), $this->getCollectionName(), @@ -262,21 +263,21 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new BulkWrite( $this->getDatabaseName(), $this->getCollectionName(), @@ -286,13 +287,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); } - public function testBulkWriteWithPipelineUpdates() + public function testBulkWriteWithPipelineUpdates(): void { if (version_compare($this->getServerVersion(), '4.2.0', '<')) { $this->markTestSkipped('Pipeline-style updates are not supported'); @@ -327,7 +328,7 @@ public function testBulkWriteWithPipelineUpdates() * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new Bulk(['ordered' => true]); diff --git a/tests/Operation/BulkWriteTest.php b/tests/Operation/BulkWriteTest.php index 7beb01f4d..aafaa4833 100644 --- a/tests/Operation/BulkWriteTest.php +++ b/tests/Operation/BulkWriteTest.php @@ -7,14 +7,14 @@ class BulkWriteTest extends TestCase { - public function testOperationsMustNotBeEmpty() + public function testOperationsMustNotBeEmpty(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$operations is empty'); new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), []); } - public function testOperationsMustBeAList() + public function testOperationsMustBeAList(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$operations is not a list (unexpected index: "1")'); @@ -23,7 +23,7 @@ public function testOperationsMustBeAList() ]); } - public function testMultipleOperationsInOneElement() + public function testMultipleOperationsInOneElement(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected one element in $operation[0], actually: 2'); @@ -35,7 +35,7 @@ public function testMultipleOperationsInOneElement() ]); } - public function testUnknownOperation() + public function testUnknownOperation(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Unknown operation type "foo" in $operations[0]'); @@ -44,7 +44,7 @@ public function testUnknownOperation() ]); } - public function testInsertOneDocumentArgumentMissing() + public function testInsertOneDocumentArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing first argument for $operations[0]["insertOne"]'); @@ -56,7 +56,7 @@ public function testInsertOneDocumentArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testInsertOneDocumentArgumentTypeCheck($document) + public function testInsertOneDocumentArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["insertOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); @@ -65,7 +65,7 @@ public function testInsertOneDocumentArgumentTypeCheck($document) ]); } - public function testDeleteManyFilterArgumentMissing() + public function testDeleteManyFilterArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing first argument for $operations[0]["deleteMany"]'); @@ -77,7 +77,7 @@ public function testDeleteManyFilterArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testDeleteManyFilterArgumentTypeCheck($document) + public function testDeleteManyFilterArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteMany"\]\[0\] to have type "array or object" but found "[\w ]+"/'); @@ -89,7 +89,7 @@ public function testDeleteManyFilterArgumentTypeCheck($document) /** * @dataProvider provideInvalidDocumentValues */ - public function testDeleteManyCollationOptionTypeCheck($collation) + public function testDeleteManyCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteMany"\]\[1\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); @@ -103,7 +103,7 @@ public function provideInvalidDocumentValues() return $this->wrapValuesForDataProvider($this->getInvalidDocumentValues()); } - public function testDeleteOneFilterArgumentMissing() + public function testDeleteOneFilterArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing first argument for $operations[0]["deleteOne"]'); @@ -115,7 +115,7 @@ public function testDeleteOneFilterArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testDeleteOneFilterArgumentTypeCheck($document) + public function testDeleteOneFilterArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); @@ -127,7 +127,7 @@ public function testDeleteOneFilterArgumentTypeCheck($document) /** * @dataProvider provideInvalidDocumentValues */ - public function testDeleteOneCollationOptionTypeCheck($collation) + public function testDeleteOneCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["deleteOne"\]\[1\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); @@ -136,7 +136,7 @@ public function testDeleteOneCollationOptionTypeCheck($collation) ]); } - public function testReplaceOneFilterArgumentMissing() + public function testReplaceOneFilterArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing first argument for $operations[0]["replaceOne"]'); @@ -148,7 +148,7 @@ public function testReplaceOneFilterArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testReplaceOneFilterArgumentTypeCheck($filter) + public function testReplaceOneFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); @@ -157,7 +157,7 @@ public function testReplaceOneFilterArgumentTypeCheck($filter) ]); } - public function testReplaceOneReplacementArgumentMissing() + public function testReplaceOneReplacementArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing second argument for $operations[0]["replaceOne"]'); @@ -169,7 +169,7 @@ public function testReplaceOneReplacementArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testReplaceOneReplacementArgumentTypeCheck($replacement) + public function testReplaceOneReplacementArgumentTypeCheck($replacement): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[1\] to have type "array or object" but found "[\w ]+"/'); @@ -178,7 +178,7 @@ public function testReplaceOneReplacementArgumentTypeCheck($replacement) ]); } - public function testReplaceOneReplacementArgumentRequiresNoOperators() + public function testReplaceOneReplacementArgumentRequiresNoOperators(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('First key in $operations[0]["replaceOne"][1] is an update operator'); @@ -190,7 +190,7 @@ public function testReplaceOneReplacementArgumentRequiresNoOperators() /** * @dataProvider provideInvalidDocumentValues */ - public function testReplaceOneCollationOptionTypeCheck($collation) + public function testReplaceOneCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); @@ -202,7 +202,7 @@ public function testReplaceOneCollationOptionTypeCheck($collation) /** * @dataProvider provideInvalidBooleanValues */ - public function testReplaceOneUpsertOptionTypeCheck($upsert) + public function testReplaceOneUpsertOptionTypeCheck($upsert): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["replaceOne"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/'); @@ -216,7 +216,7 @@ public function provideInvalidBooleanValues() return $this->wrapValuesForDataProvider($this->getInvalidBooleanValues()); } - public function testUpdateManyFilterArgumentMissing() + public function testUpdateManyFilterArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing first argument for $operations[0]["updateMany"]'); @@ -228,7 +228,7 @@ public function testUpdateManyFilterArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testUpdateManyFilterArgumentTypeCheck($filter) + public function testUpdateManyFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[0\] to have type "array or object" but found "[\w ]+"/'); @@ -237,7 +237,7 @@ public function testUpdateManyFilterArgumentTypeCheck($filter) ]); } - public function testUpdateManyUpdateArgumentMissing() + public function testUpdateManyUpdateArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing second argument for $operations[0]["updateMany"]'); @@ -249,7 +249,7 @@ public function testUpdateManyUpdateArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testUpdateManyUpdateArgumentTypeCheck($update) + public function testUpdateManyUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[1\] to have type "array or object" but found "[\w ]+"/'); @@ -258,7 +258,7 @@ public function testUpdateManyUpdateArgumentTypeCheck($update) ]); } - public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline() + public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('First key in $operations[0]["updateMany"][1] is neither an update operator nor a pipeline'); @@ -270,7 +270,7 @@ public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline() /** * @dataProvider provideInvalidArrayValues */ - public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters) + public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["arrayFilters"\] to have type "array" but found "[\w ]+"/'); @@ -282,7 +282,7 @@ public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters) /** * @dataProvider provideInvalidDocumentValues */ - public function testUpdateManyCollationOptionTypeCheck($collation) + public function testUpdateManyCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); @@ -294,7 +294,7 @@ public function testUpdateManyCollationOptionTypeCheck($collation) /** * @dataProvider provideInvalidBooleanValues */ - public function testUpdateManyUpsertOptionTypeCheck($upsert) + public function testUpdateManyUpsertOptionTypeCheck($upsert): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateMany"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/'); @@ -303,7 +303,7 @@ public function testUpdateManyUpsertOptionTypeCheck($upsert) ]); } - public function testUpdateOneFilterArgumentMissing() + public function testUpdateOneFilterArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing first argument for $operations[0]["updateOne"]'); @@ -315,7 +315,7 @@ public function testUpdateOneFilterArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testUpdateOneFilterArgumentTypeCheck($filter) + public function testUpdateOneFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[0\] to have type "array or object" but found "[\w ]+"/'); @@ -324,7 +324,7 @@ public function testUpdateOneFilterArgumentTypeCheck($filter) ]); } - public function testUpdateOneUpdateArgumentMissing() + public function testUpdateOneUpdateArgumentMissing(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Missing second argument for $operations[0]["updateOne"]'); @@ -336,7 +336,7 @@ public function testUpdateOneUpdateArgumentMissing() /** * @dataProvider provideInvalidDocumentValues */ - public function testUpdateOneUpdateArgumentTypeCheck($update) + public function testUpdateOneUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[1\] to have type "array or object" but found "[\w ]+"/'); @@ -345,7 +345,7 @@ public function testUpdateOneUpdateArgumentTypeCheck($update) ]); } - public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline() + public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('First key in $operations[0]["updateOne"][1] is neither an update operator nor a pipeline'); @@ -357,7 +357,7 @@ public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline() /** * @dataProvider provideInvalidArrayValues */ - public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters) + public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["arrayFilters"\] to have type "array" but found "[\w ]+"/'); @@ -369,7 +369,7 @@ public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters) /** * @dataProvider provideInvalidDocumentValues */ - public function testUpdateOneCollationOptionTypeCheck($collation) + public function testUpdateOneCollationOptionTypeCheck($collation): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["collation"\] to have type "array or object" but found "[\w ]+"/'); @@ -381,7 +381,7 @@ public function testUpdateOneCollationOptionTypeCheck($collation) /** * @dataProvider provideInvalidBooleanValues */ - public function testUpdateOneUpsertOptionTypeCheck($upsert) + public function testUpdateOneUpsertOptionTypeCheck($upsert): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$operations\[0\]\["updateOne"\]\[2\]\["upsert"\] to have type "boolean" but found "[\w ]+"/'); @@ -393,7 +393,7 @@ public function testUpdateOneUpsertOptionTypeCheck($upsert) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new BulkWrite( diff --git a/tests/Operation/CountDocumentsFunctionalTest.php b/tests/Operation/CountDocumentsFunctionalTest.php index 23bba406c..aaec28480 100644 --- a/tests/Operation/CountDocumentsFunctionalTest.php +++ b/tests/Operation/CountDocumentsFunctionalTest.php @@ -7,13 +7,13 @@ class CountDocumentsFunctionalTest extends FunctionalTestCase { - public function testEmptyCollection() + public function testEmptyCollection(): void { $operation = new CountDocuments($this->getDatabaseName(), $this->getCollectionName(), []); $this->assertSame(0, $operation->execute($this->getPrimaryServer())); } - public function testNonEmptyCollection() + public function testNonEmptyCollection(): void { $insertMany = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [ ['x' => 1], diff --git a/tests/Operation/CountDocumentsTest.php b/tests/Operation/CountDocumentsTest.php index 55fe0bfb8..650d45af2 100644 --- a/tests/Operation/CountDocumentsTest.php +++ b/tests/Operation/CountDocumentsTest.php @@ -10,7 +10,7 @@ class CountDocumentsTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new CountDocuments($this->getDatabaseName(), $this->getCollectionName(), $filter); @@ -19,7 +19,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new CountDocuments($this->getDatabaseName(), $this->getCollectionName(), [], $options); diff --git a/tests/Operation/CountFunctionalTest.php b/tests/Operation/CountFunctionalTest.php index 245cfdd2e..e3ff17a85 100644 --- a/tests/Operation/CountFunctionalTest.php +++ b/tests/Operation/CountFunctionalTest.php @@ -6,14 +6,15 @@ use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\InsertMany; use MongoDB\Tests\CommandObserver; + use function version_compare; class CountFunctionalTest extends FunctionalTestCase { - public function testDefaultReadConcernIsOmitted() + public function testDefaultReadConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new Count( $this->getDatabaseName(), $this->getCollectionName(), @@ -23,13 +24,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } ); } - public function testHintOption() + public function testHintOption(): void { $insertMany = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [ ['x' => 1], @@ -70,14 +71,14 @@ public function testHintOption() } } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Count( $this->getDatabaseName(), $this->getCollectionName(), @@ -87,7 +88,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/CountTest.php b/tests/Operation/CountTest.php index 06be7d4e3..623717516 100644 --- a/tests/Operation/CountTest.php +++ b/tests/Operation/CountTest.php @@ -10,7 +10,7 @@ class CountTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new Count($this->getDatabaseName(), $this->getCollectionName(), $filter); @@ -19,7 +19,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Count($this->getDatabaseName(), $this->getCollectionName(), [], $options); diff --git a/tests/Operation/CreateCollectionFunctionalTest.php b/tests/Operation/CreateCollectionFunctionalTest.php index 6874ed736..7e79969b9 100644 --- a/tests/Operation/CreateCollectionFunctionalTest.php +++ b/tests/Operation/CreateCollectionFunctionalTest.php @@ -4,14 +4,15 @@ use MongoDB\Operation\CreateCollection; use MongoDB\Tests\CommandObserver; + use function version_compare; class CreateCollectionFunctionalTest extends FunctionalTestCase { - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new CreateCollection( $this->getDatabaseName(), $this->getCollectionName(), @@ -20,20 +21,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new CreateCollection( $this->getDatabaseName(), $this->getCollectionName(), @@ -42,7 +43,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index c64188291..02d1987d6 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -10,7 +10,7 @@ class CreateCollectionTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), $options); @@ -91,13 +91,13 @@ public function provideInvalidConstructorOptions() return $options; } - public function testAutoIndexIdOptionIsDeprecated() + public function testAutoIndexIdOptionIsDeprecated(): void { - $this->assertDeprecated(function () { + $this->assertDeprecated(function (): void { new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['autoIndexId' => true]); }); - $this->assertDeprecated(function () { + $this->assertDeprecated(function (): void { new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['autoIndexId' => false]); }); } diff --git a/tests/Operation/CreateIndexesFunctionalTest.php b/tests/Operation/CreateIndexesFunctionalTest.php index 6f06c6c64..921a14aa5 100644 --- a/tests/Operation/CreateIndexesFunctionalTest.php +++ b/tests/Operation/CreateIndexesFunctionalTest.php @@ -10,6 +10,7 @@ use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\ListIndexes; use MongoDB\Tests\CommandObserver; + use function call_user_func; use function is_callable; use function sprintf; @@ -17,7 +18,7 @@ class CreateIndexesFunctionalTest extends FunctionalTestCase { - public function testCreateSparseUniqueIndex() + public function testCreateSparseUniqueIndex(): void { $indexes = [['key' => ['x' => 1], 'sparse' => true, 'unique' => true]]; @@ -25,14 +26,14 @@ public function testCreateSparseUniqueIndex() $createdIndexNames = $operation->execute($this->getPrimaryServer()); $this->assertSame('x_1', $createdIndexNames[0]); - $this->assertIndexExists('x_1', function (IndexInfo $info) { + $this->assertIndexExists('x_1', function (IndexInfo $info): void { $this->assertTrue($info->isSparse()); $this->assertTrue($info->isUnique()); $this->assertFalse($info->isTtl()); }); } - public function testCreateCompoundIndex() + public function testCreateCompoundIndex(): void { $indexes = [['key' => ['y' => -1, 'z' => 1]]]; @@ -40,14 +41,14 @@ public function testCreateCompoundIndex() $createdIndexNames = $operation->execute($this->getPrimaryServer()); $this->assertSame('y_-1_z_1', $createdIndexNames[0]); - $this->assertIndexExists('y_-1_z_1', function (IndexInfo $info) { + $this->assertIndexExists('y_-1_z_1', function (IndexInfo $info): void { $this->assertFalse($info->isSparse()); $this->assertFalse($info->isUnique()); $this->assertFalse($info->isTtl()); }); } - public function testCreateGeospatialIndex() + public function testCreateGeospatialIndex(): void { $indexes = [['key' => ['g' => '2dsphere', 'z' => 1]]]; @@ -55,14 +56,14 @@ public function testCreateGeospatialIndex() $createdIndexNames = $operation->execute($this->getPrimaryServer()); $this->assertSame('g_2dsphere_z_1', $createdIndexNames[0]); - $this->assertIndexExists('g_2dsphere_z_1', function (IndexInfo $info) { + $this->assertIndexExists('g_2dsphere_z_1', function (IndexInfo $info): void { $this->assertFalse($info->isSparse()); $this->assertFalse($info->isUnique()); $this->assertFalse($info->isTtl()); }); } - public function testCreateTTLIndex() + public function testCreateTTLIndex(): void { $indexes = [['key' => ['t' => 1], 'expireAfterSeconds' => 0, 'name' => 'my_ttl']]; @@ -70,14 +71,14 @@ public function testCreateTTLIndex() $createdIndexNames = $operation->execute($this->getPrimaryServer()); $this->assertSame('my_ttl', $createdIndexNames[0]); - $this->assertIndexExists('my_ttl', function (IndexInfo $info) { + $this->assertIndexExists('my_ttl', function (IndexInfo $info): void { $this->assertFalse($info->isSparse()); $this->assertFalse($info->isUnique()); $this->assertTrue($info->isTtl()); }); } - public function testCreateIndexes() + public function testCreateIndexes(): void { $expectedNames = ['x_1', 'y_-1_z_1', 'g_2dsphere_z_1', 'my_ttl']; @@ -93,32 +94,32 @@ public function testCreateIndexes() $this->assertSame($expectedNames, $createdIndexNames); - $this->assertIndexExists('x_1', function (IndexInfo $info) { + $this->assertIndexExists('x_1', function (IndexInfo $info): void { $this->assertTrue($info->isSparse()); $this->assertTrue($info->isUnique()); $this->assertFalse($info->isTtl()); }); - $this->assertIndexExists('y_-1_z_1', function (IndexInfo $info) { + $this->assertIndexExists('y_-1_z_1', function (IndexInfo $info): void { $this->assertFalse($info->isSparse()); $this->assertFalse($info->isUnique()); $this->assertFalse($info->isTtl()); }); - $this->assertIndexExists('g_2dsphere_z_1', function (IndexInfo $info) { + $this->assertIndexExists('g_2dsphere_z_1', function (IndexInfo $info): void { $this->assertFalse($info->isSparse()); $this->assertFalse($info->isUnique()); $this->assertFalse($info->isTtl()); }); - $this->assertIndexExists('my_ttl', function (IndexInfo $info) { + $this->assertIndexExists('my_ttl', function (IndexInfo $info): void { $this->assertFalse($info->isSparse()); $this->assertFalse($info->isUnique()); $this->assertTrue($info->isTtl()); }); } - public function testCreateConflictingIndexesWithCommand() + public function testCreateConflictingIndexesWithCommand(): void { $indexes = [ ['key' => ['x' => 1], 'sparse' => true, 'unique' => false], @@ -131,10 +132,10 @@ public function testCreateConflictingIndexesWithCommand() $operation->execute($this->getPrimaryServer()); } - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new CreateIndexes( $this->getDatabaseName(), $this->getCollectionName(), @@ -144,20 +145,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new CreateIndexes( $this->getDatabaseName(), $this->getCollectionName(), @@ -167,13 +168,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testCommitQuorumOption() + public function testCommitQuorumOption(): void { if (version_compare($this->getServerVersion(), '4.3.4', '<')) { $this->markTestSkipped('commitQuorum is not supported'); @@ -184,7 +185,7 @@ public function testCommitQuorumOption() } (new CommandObserver())->observe( - function () { + function (): void { $operation = new CreateIndexes( $this->getDatabaseName(), $this->getCollectionName(), @@ -194,13 +195,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('commitQuorum', $event['started']->getCommand()); } ); } - public function testCommitQuorumUnsupported() + public function testCommitQuorumUnsupported(): void { if (version_compare($this->getServerVersion(), '4.3.4', '>=')) { $this->markTestSkipped('commitQuorum is supported'); @@ -230,7 +231,7 @@ public function testCommitQuorumUnsupported() * @param string $indexName * @param callable $callback */ - private function assertIndexExists($indexName, $callback = null) + private function assertIndexExists(string $indexName, ?callable $callback = null): void { if ($callback !== null && ! is_callable($callback)) { throw new InvalidArgumentException('$callback is not a callable'); diff --git a/tests/Operation/CreateIndexesTest.php b/tests/Operation/CreateIndexesTest.php index 9ee0258a4..1604b0c72 100644 --- a/tests/Operation/CreateIndexesTest.php +++ b/tests/Operation/CreateIndexesTest.php @@ -8,7 +8,7 @@ class CreateIndexesTest extends TestCase { - public function testConstructorIndexesArgumentMustBeAList() + public function testConstructorIndexesArgumentMustBeAList(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$indexes is not a list (unexpected index: "1")'); @@ -18,7 +18,7 @@ public function testConstructorIndexesArgumentMustBeAList() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => ['x' => 1]]], $options); @@ -47,7 +47,7 @@ public function provideInvalidConstructorOptions() return $options; } - public function testConstructorRequiresAtLeastOneIndex() + public function testConstructorRequiresAtLeastOneIndex(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$indexes is empty'); @@ -57,7 +57,7 @@ public function testConstructorRequiresAtLeastOneIndex() /** * @dataProvider provideInvalidIndexSpecificationTypes */ - public function testConstructorRequiresIndexSpecificationsToBeAnArray($index) + public function testConstructorRequiresIndexSpecificationsToBeAnArray($index): void { $this->expectException(InvalidArgumentException::class); new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [$index]); diff --git a/tests/Operation/DatabaseCommandFunctionalTest.php b/tests/Operation/DatabaseCommandFunctionalTest.php index 0d8d2ec28..ee3251361 100644 --- a/tests/Operation/DatabaseCommandFunctionalTest.php +++ b/tests/Operation/DatabaseCommandFunctionalTest.php @@ -4,18 +4,19 @@ use MongoDB\Operation\DatabaseCommand; use MongoDB\Tests\CommandObserver; + use function version_compare; class DatabaseCommandFunctionalTest extends FunctionalTestCase { - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new DatabaseCommand( $this->getDatabaseName(), ['ping' => 1], @@ -24,7 +25,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/DatabaseCommandTest.php b/tests/Operation/DatabaseCommandTest.php index e4f82c63c..ffd3afa1f 100644 --- a/tests/Operation/DatabaseCommandTest.php +++ b/tests/Operation/DatabaseCommandTest.php @@ -10,7 +10,7 @@ class DatabaseCommandTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorCommandArgumentTypeCheck($command) + public function testConstructorCommandArgumentTypeCheck($command): void { $this->expectException(InvalidArgumentException::class); new DatabaseCommand($this->getDatabaseName(), $command); @@ -19,7 +19,7 @@ public function testConstructorCommandArgumentTypeCheck($command) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new DatabaseCommand($this->getDatabaseName(), ['ping' => 1], $options); diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php index 7a2c5b5ff..9fae16cd2 100644 --- a/tests/Operation/DeleteFunctionalTest.php +++ b/tests/Operation/DeleteFunctionalTest.php @@ -9,6 +9,7 @@ use MongoDB\Exception\BadMethodCallException; use MongoDB\Operation\Delete; use MongoDB\Tests\CommandObserver; + use function version_compare; class DeleteFunctionalTest extends FunctionalTestCase @@ -16,14 +17,14 @@ class DeleteFunctionalTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName()); } - public function testDeleteOne() + public function testDeleteOne(): void { $this->createFixtures(3); @@ -43,7 +44,7 @@ public function testDeleteOne() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testDeleteMany() + public function testDeleteMany(): void { $this->createFixtures(3); @@ -62,14 +63,14 @@ public function testDeleteMany() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Delete( $this->getDatabaseName(), $this->getCollectionName(), @@ -80,7 +81,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -102,7 +103,7 @@ public function testUnacknowledgedWriteConcern() /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesDeletedCount(DeleteResult $result) + public function testUnacknowledgedWriteConcernAccessesDeletedCount(DeleteResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -114,7 +115,7 @@ public function testUnacknowledgedWriteConcernAccessesDeletedCount(DeleteResult * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/DeleteTest.php b/tests/Operation/DeleteTest.php index c22a28801..2bbfda47f 100644 --- a/tests/Operation/DeleteTest.php +++ b/tests/Operation/DeleteTest.php @@ -4,6 +4,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Operation\Delete; + use function array_merge; class DeleteTest extends TestCase @@ -11,7 +12,7 @@ class DeleteTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new Delete($this->getDatabaseName(), $this->getCollectionName(), $filter, 0); @@ -20,7 +21,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidLimitValues */ - public function testConstructorLimitArgumentMustBeOneOrZero($limit) + public function testConstructorLimitArgumentMustBeOneOrZero($limit): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$limit must be 0 or 1'); @@ -35,7 +36,7 @@ public function provideInvalidLimitValues() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Delete($this->getDatabaseName(), $this->getCollectionName(), [], 1, $options); diff --git a/tests/Operation/DistinctFunctionalTest.php b/tests/Operation/DistinctFunctionalTest.php index f47f61faf..b329479ce 100644 --- a/tests/Operation/DistinctFunctionalTest.php +++ b/tests/Operation/DistinctFunctionalTest.php @@ -5,6 +5,7 @@ use MongoDB\Driver\BulkWrite; use MongoDB\Operation\Distinct; use MongoDB\Tests\CommandObserver; + use function is_scalar; use function json_encode; use function usort; @@ -12,10 +13,10 @@ class DistinctFunctionalTest extends FunctionalTestCase { - public function testDefaultReadConcernIsOmitted() + public function testDefaultReadConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new Distinct( $this->getDatabaseName(), $this->getCollectionName(), @@ -26,20 +27,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } ); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Distinct( $this->getDatabaseName(), $this->getCollectionName(), @@ -50,7 +51,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -59,7 +60,7 @@ function (array $event) { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOption(array $typeMap, array $expectedDocuments) + public function testTypeMapOption(array $typeMap, array $expectedDocuments): void { $bulkWrite = new BulkWrite(['ordered' => true]); $bulkWrite->insert([ diff --git a/tests/Operation/DistinctTest.php b/tests/Operation/DistinctTest.php index 95ea2537a..dc168bf91 100644 --- a/tests/Operation/DistinctTest.php +++ b/tests/Operation/DistinctTest.php @@ -10,7 +10,7 @@ class DistinctTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', $filter); @@ -19,7 +19,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', [], $options); diff --git a/tests/Operation/DropCollectionFunctionalTest.php b/tests/Operation/DropCollectionFunctionalTest.php index a52a7c3ba..50fcc3ac6 100644 --- a/tests/Operation/DropCollectionFunctionalTest.php +++ b/tests/Operation/DropCollectionFunctionalTest.php @@ -6,15 +6,16 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListCollections; use MongoDB\Tests\CommandObserver; + use function sprintf; use function version_compare; class DropCollectionFunctionalTest extends FunctionalTestCase { - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new DropCollection( $this->getDatabaseName(), $this->getCollectionName(), @@ -23,13 +24,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); } - public function testDropExistingCollection() + public function testDropExistingCollection(): void { $server = $this->getPrimaryServer(); @@ -47,7 +48,7 @@ public function testDropExistingCollection() /** * @depends testDropExistingCollection */ - public function testDropNonexistentCollection() + public function testDropNonexistentCollection(): void { $this->assertCollectionDoesNotExist($this->getCollectionName()); @@ -59,14 +60,14 @@ public function testDropNonexistentCollection() $this->assertIsObject($commandResult); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new DropCollection( $this->getDatabaseName(), $this->getCollectionName(), @@ -75,7 +76,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -87,7 +88,7 @@ function (array $event) { * * @param string $collectionName */ - private function assertCollectionDoesNotExist($collectionName) + private function assertCollectionDoesNotExist(string $collectionName): void { $operation = new ListCollections($this->getDatabaseName()); $collections = $operation->execute($this->getPrimaryServer()); diff --git a/tests/Operation/DropCollectionTest.php b/tests/Operation/DropCollectionTest.php index 61d9359fa..45042e6b9 100644 --- a/tests/Operation/DropCollectionTest.php +++ b/tests/Operation/DropCollectionTest.php @@ -10,7 +10,7 @@ class DropCollectionTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new DropCollection($this->getDatabaseName(), $this->getCollectionName(), $options); diff --git a/tests/Operation/DropDatabaseFunctionalTest.php b/tests/Operation/DropDatabaseFunctionalTest.php index fab1cbdcd..5e504bd3a 100644 --- a/tests/Operation/DropDatabaseFunctionalTest.php +++ b/tests/Operation/DropDatabaseFunctionalTest.php @@ -7,15 +7,16 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListDatabases; use MongoDB\Tests\CommandObserver; + use function sprintf; use function version_compare; class DropDatabaseFunctionalTest extends FunctionalTestCase { - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new DropDatabase( $this->getDatabaseName(), ['writeConcern' => $this->createDefaultWriteConcern()] @@ -23,13 +24,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); } - public function testDropExistingDatabase() + public function testDropExistingDatabase(): void { $server = $this->getPrimaryServer(); @@ -46,7 +47,7 @@ public function testDropExistingDatabase() /** * @depends testDropExistingDatabase */ - public function testDropNonexistentDatabase() + public function testDropNonexistentDatabase(): void { $server = $this->getPrimaryServer(); @@ -59,14 +60,14 @@ public function testDropNonexistentDatabase() $operation->execute($server); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new DropDatabase( $this->getDatabaseName(), ['session' => $this->createSession()] @@ -74,7 +75,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -86,7 +87,7 @@ function (array $event) { * @param Server $server * @param string $databaseName */ - private function assertDatabaseDoesNotExist(Server $server, $databaseName) + private function assertDatabaseDoesNotExist(Server $server, string $databaseName): void { $operation = new ListDatabases(); $databases = $operation->execute($server); diff --git a/tests/Operation/DropDatabaseTest.php b/tests/Operation/DropDatabaseTest.php index 45d159b0b..06e33d961 100644 --- a/tests/Operation/DropDatabaseTest.php +++ b/tests/Operation/DropDatabaseTest.php @@ -10,7 +10,7 @@ class DropDatabaseTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new DropDatabase($this->getDatabaseName(), $options); diff --git a/tests/Operation/DropIndexesFunctionalTest.php b/tests/Operation/DropIndexesFunctionalTest.php index b9d104c14..a90f387f1 100644 --- a/tests/Operation/DropIndexesFunctionalTest.php +++ b/tests/Operation/DropIndexesFunctionalTest.php @@ -8,6 +8,7 @@ use MongoDB\Operation\DropIndexes; use MongoDB\Operation\ListIndexes; use MongoDB\Tests\CommandObserver; + use function call_user_func; use function is_callable; use function sprintf; @@ -15,13 +16,13 @@ class DropIndexesFunctionalTest extends FunctionalTestCase { - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => ['x' => 1]]]); $operation->execute($this->getPrimaryServer()); (new CommandObserver())->observe( - function () { + function (): void { $operation = new DropIndexes( $this->getDatabaseName(), $this->getCollectionName(), @@ -31,13 +32,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); } - public function testDropOneIndexByName() + public function testDropOneIndexByName(): void { $indexes = [['key' => ['x' => 1]]]; @@ -60,7 +61,7 @@ public function testDropOneIndexByName() } } - public function testDropAllIndexesByWildcard() + public function testDropAllIndexesByWildcard(): void { $indexes = [ ['key' => ['x' => 1]], @@ -92,7 +93,7 @@ public function testDropAllIndexesByWildcard() } } - public function testDropByIndexInfo() + public function testDropByIndexInfo(): void { $info = new IndexInfo([ 'v' => 1, @@ -120,7 +121,7 @@ public function testDropByIndexInfo() } } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); @@ -130,7 +131,7 @@ public function testSessionOption() $operation->execute($this->getPrimaryServer()); (new CommandObserver())->observe( - function () { + function (): void { $operation = new DropIndexes( $this->getDatabaseName(), $this->getCollectionName(), @@ -140,7 +141,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -156,7 +157,7 @@ function (array $event) { * * @param callable $callback */ - private function assertIndexExists($indexName, $callback = null) + private function assertIndexExists($indexName, ?callable $callback = null): void { if ($callback !== null && ! is_callable($callback)) { throw new InvalidArgumentException('$callback is not a callable'); diff --git a/tests/Operation/DropIndexesTest.php b/tests/Operation/DropIndexesTest.php index bf947f862..ab09aeadf 100644 --- a/tests/Operation/DropIndexesTest.php +++ b/tests/Operation/DropIndexesTest.php @@ -7,7 +7,7 @@ class DropIndexesTest extends TestCase { - public function testDropIndexShouldNotAllowEmptyIndexName() + public function testDropIndexShouldNotAllowEmptyIndexName(): void { $this->expectException(InvalidArgumentException::class); new DropIndexes($this->getDatabaseName(), $this->getCollectionName(), ''); @@ -16,7 +16,7 @@ public function testDropIndexShouldNotAllowEmptyIndexName() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new DropIndexes($this->getDatabaseName(), $this->getCollectionName(), '*', $options); diff --git a/tests/Operation/EstimatedDocumentCountTest.php b/tests/Operation/EstimatedDocumentCountTest.php index ea8231a26..803e1194d 100644 --- a/tests/Operation/EstimatedDocumentCountTest.php +++ b/tests/Operation/EstimatedDocumentCountTest.php @@ -10,7 +10,7 @@ class EstimatedDocumentCountTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new EstimatedDocumentCount($this->getDatabaseName(), $this->getCollectionName(), $options); diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php index e10c5157d..9ead7aec1 100644 --- a/tests/Operation/ExplainFunctionalTest.php +++ b/tests/Operation/ExplainFunctionalTest.php @@ -21,6 +21,7 @@ use MongoDB\Operation\UpdateMany; use MongoDB\Operation\UpdateOne; use MongoDB\Tests\CommandObserver; + use function version_compare; class ExplainFunctionalTest extends FunctionalTestCase @@ -28,7 +29,7 @@ class ExplainFunctionalTest extends FunctionalTestCase /** * @dataProvider provideVerbosityInformation */ - public function testCount($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testCount($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -43,7 +44,7 @@ public function testCount($verbosity, $executionStatsExpected, $allPlansExecutio /** * @dataProvider provideVerbosityInformation */ - public function testDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -60,7 +61,7 @@ public function testDelete($verbosity, $executionStatsExpected, $allPlansExecuti /** * @dataProvider provideVerbosityInformation */ - public function testDeleteMany($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testDeleteMany($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -77,7 +78,7 @@ public function testDeleteMany($verbosity, $executionStatsExpected, $allPlansExe /** * @dataProvider provideVerbosityInformation */ - public function testDeleteOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testDeleteOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -94,7 +95,7 @@ public function testDeleteOne($verbosity, $executionStatsExpected, $allPlansExec /** * @dataProvider provideVerbosityInformation */ - public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('Explaining distinct command requires server version >= 3.2'); @@ -111,7 +112,7 @@ public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecu /** * @dataProvider provideVerbosityInformation */ - public function testFindAndModify($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testFindAndModify($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('Explaining findAndModify command requires server version >= 3.2'); @@ -128,7 +129,7 @@ public function testFindAndModify($verbosity, $executionStatsExpected, $allPlans /** * @dataProvider provideVerbosityInformation */ - public function testFind($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testFind($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -140,7 +141,7 @@ public function testFind($verbosity, $executionStatsExpected, $allPlansExecution $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected); } - public function testFindMaxAwait() + public function testFindMaxAwait(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('maxAwaitTimeMS option is not supported'); @@ -170,11 +171,11 @@ public function testFindMaxAwait() $operation = new Find($databaseName, $cappedCollectionName, [], ['cursorType' => Find::TAILABLE_AWAIT, 'maxAwaitTimeMS' => $maxAwaitTimeMS]); (new CommandObserver())->observe( - function () use ($operation) { + function () use ($operation): void { $explainOperation = new Explain($this->getDatabaseName(), $operation, ['typeMap' => ['root' => 'array', 'document' => 'array']]); $explainOperation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $command = $event['started']->getCommand(); $this->assertObjectNotHasAttribute('maxAwaitTimeMS', $command->explain); $this->assertObjectHasAttribute('tailable', $command->explain); @@ -183,7 +184,7 @@ function (array $event) { ); } - public function testFindModifiers() + public function testFindModifiers(): void { $this->createFixtures(3); @@ -195,11 +196,11 @@ public function testFindModifiers() ); (new CommandObserver())->observe( - function () use ($operation) { + function () use ($operation): void { $explainOperation = new Explain($this->getDatabaseName(), $operation, ['typeMap' => ['root' => 'array', 'document' => 'array']]); $explainOperation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $command = $event['started']->getCommand(); $this->assertObjectHasAttribute('sort', $command->explain); $this->assertObjectNotHasAttribute('modifiers', $command->explain); @@ -210,7 +211,7 @@ function (array $event) { /** * @dataProvider provideVerbosityInformation */ - public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(1); @@ -225,7 +226,7 @@ public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecut /** * @dataProvider provideVerbosityInformation */ - public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('Explaining findOneAndDelete command requires server version >= 3.2'); @@ -242,7 +243,7 @@ public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPl /** * @dataProvider provideVerbosityInformation */ - public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('Explaining findOneAndReplace command requires server version >= 3.2'); @@ -259,7 +260,7 @@ public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allP /** * @dataProvider provideVerbosityInformation */ - public function testFindOneAndUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testFindOneAndUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('Explaining findOneAndUpdate command requires server version >= 3.2'); @@ -276,7 +277,7 @@ public function testFindOneAndUpdate($verbosity, $executionStatsExpected, $allPl /** * @dataProvider provideVerbosityInformation */ - public function testUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -291,7 +292,7 @@ public function testUpdate($verbosity, $executionStatsExpected, $allPlansExecuti $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected); } - public function testUpdateBypassDocumentValidationSetWhenTrue() + public function testUpdateBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); @@ -300,7 +301,7 @@ public function testUpdateBypassDocumentValidationSetWhenTrue() $this->createFixtures(3); (new CommandObserver())->observe( - function () { + function (): void { $operation = new Update( $this->getDatabaseName(), $this->getCollectionName(), @@ -312,7 +313,7 @@ function () { $explainOperation = new Explain($this->getDatabaseName(), $operation); $result = $explainOperation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute( 'bypassDocumentValidation', $event['started']->getCommand()->explain @@ -322,7 +323,7 @@ function (array $event) { ); } - public function testUpdateBypassDocumentValidationUnsetWhenFalse() + public function testUpdateBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); @@ -331,7 +332,7 @@ public function testUpdateBypassDocumentValidationUnsetWhenFalse() $this->createFixtures(3); (new CommandObserver())->observe( - function () { + function (): void { $operation = new Update( $this->getDatabaseName(), $this->getCollectionName(), @@ -343,7 +344,7 @@ function () { $explainOperation = new Explain($this->getDatabaseName(), $operation); $result = $explainOperation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute( 'bypassDocumentValidation', $event['started']->getCommand()->explain @@ -355,7 +356,7 @@ function (array $event) { /** * @dataProvider provideVerbosityInformation */ - public function testUpdateMany($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testUpdateMany($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -373,7 +374,7 @@ public function testUpdateMany($verbosity, $executionStatsExpected, $allPlansExe /** * @dataProvider provideVerbosityInformation */ - public function testUpdateOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testUpdateOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { $this->createFixtures(3); @@ -388,7 +389,7 @@ public function testUpdateOne($verbosity, $executionStatsExpected, $allPlansExec $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected); } - public function testAggregate() + public function testAggregate(): void { if (version_compare($this->getServerVersion(), '4.0.0', '<')) { $this->markTestSkipped('Explaining aggregate command requires server version >= 4.0'); @@ -408,7 +409,7 @@ public function testAggregate() /** * @dataProvider provideVerbosityInformation */ - public function testAggregateOptimizedToQuery($verbosity, $executionStatsExpected, $allPlansExecutionExpected) + public function testAggregateOptimizedToQuery($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { if (version_compare($this->getServerVersion(), '4.2.0', '<')) { $this->markTestSkipped('MongoDB < 4.2 does not optimize simple aggregation pipelines'); @@ -434,7 +435,7 @@ public function provideVerbosityInformation() ]; } - private function assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected, $stagesExpected = false) + private function assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected, $stagesExpected = false): void { if ($stagesExpected) { $this->assertArrayHasKey('stages', $result); @@ -459,7 +460,7 @@ private function assertExplainResult($result, $executionStatsExpected, $allPlans * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/ExplainTest.php b/tests/Operation/ExplainTest.php index 945e300a4..184705662 100644 --- a/tests/Operation/ExplainTest.php +++ b/tests/Operation/ExplainTest.php @@ -11,7 +11,7 @@ class ExplainTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $explainable = $this->getMockBuilder(Explainable::class)->getMock(); $this->expectException(InvalidArgumentException::class); diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index 10539797b..156632f0e 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -7,6 +7,7 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\FindAndModify; use MongoDB\Tests\CommandObserver; + use function version_compare; class FindAndModifyFunctionalTest extends FunctionalTestCase @@ -14,13 +15,13 @@ class FindAndModifyFunctionalTest extends FunctionalTestCase /** * @see https://jira.mongodb.org/browse/PHPLIB-344 */ - public function testManagerReadConcernIsOmitted() + public function testManagerReadConcernIsOmitted(): void { $manager = static::createTestManager(null, ['readConcernLevel' => 'majority']); $server = $manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY)); (new CommandObserver())->observe( - function () use ($server) { + function () use ($server): void { $operation = new FindAndModify( $this->getDatabaseName(), $this->getCollectionName(), @@ -29,16 +30,16 @@ function () use ($server) { $operation->execute($server); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } ); } - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new FindAndModify( $this->getDatabaseName(), $this->getCollectionName(), @@ -47,20 +48,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new FindAndModify( $this->getDatabaseName(), $this->getCollectionName(), @@ -69,20 +70,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new FindAndModify( $this->getDatabaseName(), $this->getCollectionName(), @@ -91,21 +92,21 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new FindAndModify( $this->getDatabaseName(), $this->getCollectionName(), @@ -114,7 +115,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); @@ -123,7 +124,7 @@ function (array $event) { /** * @dataProvider provideTypeMapOptionsAndExpectedDocument */ - public function testTypeMapOption(array $typeMap = null, $expectedDocument) + public function testTypeMapOption(?array $typeMap = null, $expectedDocument): void { $this->createFixtures(1); @@ -175,7 +176,7 @@ public function provideTypeMapOptionsAndExpectedDocument() * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/FindAndModifyTest.php b/tests/Operation/FindAndModifyTest.php index 7f5cb99cc..4506d59e8 100644 --- a/tests/Operation/FindAndModifyTest.php +++ b/tests/Operation/FindAndModifyTest.php @@ -10,7 +10,7 @@ class FindAndModifyTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new FindAndModify($this->getDatabaseName(), $this->getCollectionName(), $options); @@ -79,7 +79,7 @@ public function provideInvalidConstructorOptions() return $options; } - public function testConstructorUpdateAndRemoveOptionsAreMutuallyExclusive() + public function testConstructorUpdateAndRemoveOptionsAreMutuallyExclusive(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('The "remove" option must be true or an "update" document must be specified, but not both'); diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php index 0b22cdf53..957ec6dc2 100644 --- a/tests/Operation/FindFunctionalTest.php +++ b/tests/Operation/FindFunctionalTest.php @@ -8,15 +8,16 @@ use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\Find; use MongoDB\Tests\CommandObserver; + use function microtime; use function version_compare; class FindFunctionalTest extends FunctionalTestCase { - public function testDefaultReadConcernIsOmitted() + public function testDefaultReadConcernIsOmitted(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new Find( $this->getDatabaseName(), $this->getCollectionName(), @@ -26,13 +27,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } ); } - public function testHintOption() + public function testHintOption(): void { $bulkWrite = new BulkWrite(); $bulkWrite->insert(['_id' => 1, 'x' => 1]); @@ -83,14 +84,14 @@ public function testHintOption() } } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Find( $this->getDatabaseName(), $this->getCollectionName(), @@ -100,7 +101,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); @@ -109,7 +110,7 @@ function (array $event) { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOption(array $typeMap, array $expectedDocuments) + public function testTypeMapOption(array $typeMap, array $expectedDocuments): void { $this->createFixtures(3); @@ -149,7 +150,7 @@ public function provideTypeMapOptionsAndExpectedDocuments() ]; } - public function testMaxAwaitTimeMS() + public function testMaxAwaitTimeMS(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('maxAwaitTimeMS option is not supported'); @@ -217,7 +218,7 @@ public function testMaxAwaitTimeMS() $this->assertFalse($cursor->valid()); } - public function testReadPreferenceWithinTransaction() + public function testReadPreferenceWithinTransaction(): void { $this->skipIfTransactionsAreNotSupported(); @@ -258,7 +259,7 @@ public function testReadPreferenceWithinTransaction() * @param integer $n * @param array $executeBulkWriteOptions */ - private function createFixtures($n, array $executeBulkWriteOptions = []) + private function createFixtures(int $n, array $executeBulkWriteOptions = []): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/FindOneAndDeleteTest.php b/tests/Operation/FindOneAndDeleteTest.php index 306ec3568..c2a325e6f 100644 --- a/tests/Operation/FindOneAndDeleteTest.php +++ b/tests/Operation/FindOneAndDeleteTest.php @@ -10,7 +10,7 @@ class FindOneAndDeleteTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), $filter); @@ -19,7 +19,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), [], $options); diff --git a/tests/Operation/FindOneAndReplaceTest.php b/tests/Operation/FindOneAndReplaceTest.php index 974d413a3..ad7cbd36b 100644 --- a/tests/Operation/FindOneAndReplaceTest.php +++ b/tests/Operation/FindOneAndReplaceTest.php @@ -10,7 +10,7 @@ class FindOneAndReplaceTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), $filter, []); @@ -19,13 +19,13 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorReplacementArgumentTypeCheck($replacement) + public function testConstructorReplacementArgumentTypeCheck($replacement): void { $this->expectException(InvalidArgumentException::class); new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement); } - public function testConstructorReplacementArgumentRequiresNoOperators() + public function testConstructorReplacementArgumentRequiresNoOperators(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('First key in $replacement argument is an update operator'); @@ -35,7 +35,7 @@ public function testConstructorReplacementArgumentRequiresNoOperators() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], [], $options); @@ -59,7 +59,7 @@ public function provideInvalidConstructorOptions() /** * @dataProvider provideInvalidConstructorReturnDocumentOptions */ - public function testConstructorReturnDocumentOption($returnDocument) + public function testConstructorReturnDocumentOption($returnDocument): void { $this->expectException(InvalidArgumentException::class); new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], [], ['returnDocument' => $returnDocument]); diff --git a/tests/Operation/FindOneAndUpdateTest.php b/tests/Operation/FindOneAndUpdateTest.php index 1391b7623..8bf142148 100644 --- a/tests/Operation/FindOneAndUpdateTest.php +++ b/tests/Operation/FindOneAndUpdateTest.php @@ -10,7 +10,7 @@ class FindOneAndUpdateTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), $filter, []); @@ -19,13 +19,13 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorUpdateArgumentTypeCheck($update) + public function testConstructorUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], $update); } - public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline() + public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline'); @@ -35,7 +35,7 @@ public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], ['$set' => ['x' => 1]], $options); @@ -59,7 +59,7 @@ public function provideInvalidConstructorOptions() /** * @dataProvider provideInvalidConstructorReturnDocumentOptions */ - public function testConstructorReturnDocumentOption($returnDocument) + public function testConstructorReturnDocumentOption($returnDocument): void { $this->expectException(InvalidArgumentException::class); new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], [], ['returnDocument' => $returnDocument]); diff --git a/tests/Operation/FindOneFunctionalTest.php b/tests/Operation/FindOneFunctionalTest.php index 62fac8287..e15e6967c 100644 --- a/tests/Operation/FindOneFunctionalTest.php +++ b/tests/Operation/FindOneFunctionalTest.php @@ -10,7 +10,7 @@ class FindOneFunctionalTest extends FunctionalTestCase /** * @dataProvider provideTypeMapOptionsAndExpectedDocument */ - public function testTypeMapOption(array $typeMap, $expectedDocument) + public function testTypeMapOption(array $typeMap, $expectedDocument): void { $this->createFixtures(1); @@ -43,7 +43,7 @@ public function provideTypeMapOptionsAndExpectedDocument() * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php index 4464ea5a8..3bf09c7bc 100644 --- a/tests/Operation/FindTest.php +++ b/tests/Operation/FindTest.php @@ -10,7 +10,7 @@ class FindTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new Find($this->getDatabaseName(), $this->getCollectionName(), $filter); @@ -19,7 +19,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Find($this->getDatabaseName(), $this->getCollectionName(), [], $options); @@ -128,20 +128,20 @@ public function provideInvalidConstructorOptions() return $options; } - public function testSnapshotOptionIsDeprecated() + public function testSnapshotOptionIsDeprecated(): void { - $this->assertDeprecated(function () { + $this->assertDeprecated(function (): void { new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['snapshot' => true]); }); - $this->assertDeprecated(function () { + $this->assertDeprecated(function (): void { new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['snapshot' => false]); }); } - public function testMaxScanOptionIsDeprecated() + public function testMaxScanOptionIsDeprecated(): void { - $this->assertDeprecated(function () { + $this->assertDeprecated(function (): void { new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['maxScan' => 1]); }); } @@ -154,7 +154,7 @@ private function getInvalidHintValues() /** * @dataProvider provideInvalidConstructorCursorTypeOptions */ - public function testConstructorCursorTypeOption($cursorType) + public function testConstructorCursorTypeOption($cursorType): void { $this->expectException(InvalidArgumentException::class); new Find($this->getDatabaseName(), $this->getCollectionName(), [], ['cursorType' => $cursorType]); diff --git a/tests/Operation/FunctionalTestCase.php b/tests/Operation/FunctionalTestCase.php index 6af42b3cb..4cf9f33cb 100644 --- a/tests/Operation/FunctionalTestCase.php +++ b/tests/Operation/FunctionalTestCase.php @@ -11,14 +11,14 @@ */ abstract class FunctionalTestCase extends BaseFunctionalTestCase { - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->dropCollection(); } - public function tearDown() : void + public function tearDown(): void { if ($this->hasFailed()) { return; diff --git a/tests/Operation/InsertManyFunctionalTest.php b/tests/Operation/InsertManyFunctionalTest.php index 262672930..72418928f 100644 --- a/tests/Operation/InsertManyFunctionalTest.php +++ b/tests/Operation/InsertManyFunctionalTest.php @@ -10,6 +10,7 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\InsertMany; use MongoDB\Tests\CommandObserver; + use function version_compare; class InsertManyFunctionalTest extends FunctionalTestCase @@ -17,14 +18,14 @@ class InsertManyFunctionalTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName()); } - public function testInsertMany() + public function testInsertMany(): void { $documents = [ ['_id' => 'foo', 'x' => 11], @@ -55,14 +56,14 @@ public function testInsertMany() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new InsertMany( $this->getDatabaseName(), $this->getCollectionName(), @@ -72,20 +73,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new InsertMany( $this->getDatabaseName(), $this->getCollectionName(), @@ -95,21 +96,21 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new InsertMany( $this->getDatabaseName(), $this->getCollectionName(), @@ -119,7 +120,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); @@ -141,7 +142,7 @@ public function testUnacknowledgedWriteConcern() /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertManyResult $result) + public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertManyResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -151,7 +152,7 @@ public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertManyRe /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertManyResult $result) + public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertManyResult $result): void { $this->assertInstanceOf(ObjectId::class, $result->getInsertedIds()[0]); } diff --git a/tests/Operation/InsertManyTest.php b/tests/Operation/InsertManyTest.php index 38955fd58..e8326f100 100644 --- a/tests/Operation/InsertManyTest.php +++ b/tests/Operation/InsertManyTest.php @@ -7,14 +7,14 @@ class InsertManyTest extends TestCase { - public function testConstructorDocumentsMustNotBeEmpty() + public function testConstructorDocumentsMustNotBeEmpty(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$documents is empty'); new InsertMany($this->getDatabaseName(), $this->getCollectionName(), []); } - public function testConstructorDocumentsMustBeAList() + public function testConstructorDocumentsMustBeAList(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$documents is not a list (unexpected index: "1")'); @@ -24,7 +24,7 @@ public function testConstructorDocumentsMustBeAList() /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorDocumentsArgumentElementTypeChecks($document) + public function testConstructorDocumentsArgumentElementTypeChecks($document): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$documents[0\] to have type "array or object" but found "[\w ]+"/'); @@ -34,7 +34,7 @@ public function testConstructorDocumentsArgumentElementTypeChecks($document) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [['x' => 1]], $options); diff --git a/tests/Operation/InsertOneFunctionalTest.php b/tests/Operation/InsertOneFunctionalTest.php index 51603bb01..d0c8f374e 100644 --- a/tests/Operation/InsertOneFunctionalTest.php +++ b/tests/Operation/InsertOneFunctionalTest.php @@ -10,6 +10,7 @@ use MongoDB\Model\BSONDocument; use MongoDB\Operation\InsertOne; use MongoDB\Tests\CommandObserver; + use function version_compare; class InsertOneFunctionalTest extends FunctionalTestCase @@ -17,7 +18,7 @@ class InsertOneFunctionalTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -27,7 +28,7 @@ public function setUp() : void /** * @dataProvider provideDocumentWithExistingId */ - public function testInsertOneWithExistingId($document) + public function testInsertOneWithExistingId($document): void { $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document); $result = $operation->execute($this->getPrimaryServer()); @@ -52,7 +53,7 @@ public function provideDocumentWithExistingId() ]; } - public function testInsertOneWithGeneratedId() + public function testInsertOneWithGeneratedId(): void { $document = ['x' => 11]; @@ -70,14 +71,14 @@ public function testInsertOneWithGeneratedId() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new InsertOne( $this->getDatabaseName(), $this->getCollectionName(), @@ -87,20 +88,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new InsertOne( $this->getDatabaseName(), $this->getCollectionName(), @@ -110,21 +111,21 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new InsertOne( $this->getDatabaseName(), $this->getCollectionName(), @@ -134,7 +135,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); @@ -156,7 +157,7 @@ public function testUnacknowledgedWriteConcern() /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertOneResult $result) + public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertOneResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -166,7 +167,7 @@ public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertOneRes /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertOneResult $result) + public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertOneResult $result): void { $this->assertInstanceOf(ObjectId::class, $result->getInsertedId()); } diff --git a/tests/Operation/InsertOneTest.php b/tests/Operation/InsertOneTest.php index 2a91f8cc0..f957ba9d3 100644 --- a/tests/Operation/InsertOneTest.php +++ b/tests/Operation/InsertOneTest.php @@ -10,7 +10,7 @@ class InsertOneTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorDocumentArgumentTypeCheck($document) + public function testConstructorDocumentArgumentTypeCheck($document): void { $this->expectException(InvalidArgumentException::class); new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document); @@ -19,7 +19,7 @@ public function testConstructorDocumentArgumentTypeCheck($document) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $options); diff --git a/tests/Operation/ListCollectionNamesFunctionalTest.php b/tests/Operation/ListCollectionNamesFunctionalTest.php index dbb111ab7..8f222fa5a 100644 --- a/tests/Operation/ListCollectionNamesFunctionalTest.php +++ b/tests/Operation/ListCollectionNamesFunctionalTest.php @@ -6,11 +6,12 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListCollectionNames; use MongoDB\Tests\CommandObserver; + use function version_compare; class ListCollectionNamesFunctionalTest extends FunctionalTestCase { - public function testListCollectionNamesForNewlyCreatedDatabase() + public function testListCollectionNamesForNewlyCreatedDatabase(): void { $server = $this->getPrimaryServer(); @@ -30,14 +31,14 @@ public function testListCollectionNamesForNewlyCreatedDatabase() } } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListCollectionNames( $this->getDatabaseName(), ['session' => $this->createSession()] @@ -45,7 +46,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/ListCollectionsFunctionalTest.php b/tests/Operation/ListCollectionsFunctionalTest.php index f42f83b82..4b1fdb7e6 100644 --- a/tests/Operation/ListCollectionsFunctionalTest.php +++ b/tests/Operation/ListCollectionsFunctionalTest.php @@ -8,11 +8,12 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListCollections; use MongoDB\Tests\CommandObserver; + use function version_compare; class ListCollectionsFunctionalTest extends FunctionalTestCase { - public function testListCollectionsForNewlyCreatedDatabase() + public function testListCollectionsForNewlyCreatedDatabase(): void { $server = $this->getPrimaryServer(); @@ -42,7 +43,7 @@ public function testListCollectionsForNewlyCreatedDatabase() * @group matrix-testing-exclude-server-5.0-driver-4.0 * @group matrix-testing-exclude-server-5.0-driver-4.2 */ - public function testIdIndexAndInfo() + public function testIdIndexAndInfo(): void { if (version_compare($this->getServerVersion(), '3.4.0', '<')) { $this->markTestSkipped('idIndex and info are not supported'); @@ -66,7 +67,7 @@ public function testIdIndexAndInfo() } } - public function testListCollectionsForNonexistentDatabase() + public function testListCollectionsForNonexistentDatabase(): void { $server = $this->getPrimaryServer(); @@ -79,14 +80,14 @@ public function testListCollectionsForNonexistentDatabase() $this->assertCount(0, $collections); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListCollections( $this->getDatabaseName(), ['session' => $this->createSession()] @@ -94,7 +95,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/ListDatabaseNamesFunctionalTest.php b/tests/Operation/ListDatabaseNamesFunctionalTest.php index 2553c81fa..8536fcbea 100644 --- a/tests/Operation/ListDatabaseNamesFunctionalTest.php +++ b/tests/Operation/ListDatabaseNamesFunctionalTest.php @@ -5,11 +5,12 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListDatabaseNames; use MongoDB\Tests\CommandObserver; + use function version_compare; class ListDatabaseNamesFunctionalTest extends FunctionalTestCase { - public function testListDatabaseNames() + public function testListDatabaseNames(): void { $server = $this->getPrimaryServer(); @@ -19,12 +20,12 @@ public function testListDatabaseNames() $databases = null; (new CommandObserver())->observe( - function () use (&$databases, $server) { + function () use (&$databases, $server): void { $operation = new ListDatabaseNames(); $databases = $operation->execute($server); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('authorizedDatabases', $event['started']->getCommand()); $this->assertSame(true, $event['started']->getCommand()->nameOnly); } @@ -35,24 +36,24 @@ function (array $event) { } } - public function testAuthorizedDatabasesOption() + public function testAuthorizedDatabasesOption(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListDatabaseNames( ['authorizedDatabases' => true] ); $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('authorizedDatabases', $event['started']->getCommand()); $this->assertSame(true, $event['started']->getCommand()->nameOnly); } ); } - public function testFilterOption() + public function testFilterOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('listDatabase command "filter" option is not supported'); @@ -73,21 +74,21 @@ public function testFilterOption() } } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListDatabaseNames( ['session' => $this->createSession()] ); $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/ListDatabasesFunctionalTest.php b/tests/Operation/ListDatabasesFunctionalTest.php index 6e9bb1e58..1346a5387 100644 --- a/tests/Operation/ListDatabasesFunctionalTest.php +++ b/tests/Operation/ListDatabasesFunctionalTest.php @@ -7,11 +7,12 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListDatabases; use MongoDB\Tests\CommandObserver; + use function version_compare; class ListDatabasesFunctionalTest extends FunctionalTestCase { - public function testListDatabases() + public function testListDatabases(): void { $server = $this->getPrimaryServer(); @@ -21,12 +22,12 @@ public function testListDatabases() $databases = null; (new CommandObserver())->observe( - function () use (&$databases, $server) { + function () use (&$databases, $server): void { $operation = new ListDatabases(); $databases = $operation->execute($server); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('authorizedDatabases', $event['started']->getCommand()); } ); @@ -38,23 +39,23 @@ function (array $event) { } } - public function testAuthorizedDatabasesOption() + public function testAuthorizedDatabasesOption(): void { (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListDatabases( ['authorizedDatabases' => true] ); $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('authorizedDatabases', $event['started']->getCommand()); } ); } - public function testFilterOption() + public function testFilterOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('listDatabase command "filter" option is not supported'); @@ -79,21 +80,21 @@ public function testFilterOption() } } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListDatabases( ['session' => $this->createSession()] ); $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/ListIndexesFunctionalTest.php b/tests/Operation/ListIndexesFunctionalTest.php index 7c5fb8222..d0522edd9 100644 --- a/tests/Operation/ListIndexesFunctionalTest.php +++ b/tests/Operation/ListIndexesFunctionalTest.php @@ -8,11 +8,12 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListIndexes; use MongoDB\Tests\CommandObserver; + use function version_compare; class ListIndexesFunctionalTest extends FunctionalTestCase { - public function testListIndexesForNewlyCreatedCollection() + public function testListIndexesForNewlyCreatedCollection(): void { $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); $operation->execute($this->getPrimaryServer()); @@ -35,7 +36,7 @@ public function testListIndexesForNewlyCreatedCollection() } } - public function testListIndexesForNonexistentCollection() + public function testListIndexesForNonexistentCollection(): void { $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName()); $operation->execute($this->getPrimaryServer()); @@ -46,14 +47,14 @@ public function testListIndexesForNonexistentCollection() $this->assertCount(0, $indexes); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new ListIndexes( $this->getDatabaseName(), $this->getCollectionName(), @@ -62,7 +63,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); diff --git a/tests/Operation/ListIndexesTest.php b/tests/Operation/ListIndexesTest.php index c8b845080..dd4c8978d 100644 --- a/tests/Operation/ListIndexesTest.php +++ b/tests/Operation/ListIndexesTest.php @@ -10,7 +10,7 @@ class ListIndexesTest extends TestCase /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new ListIndexes($this->getDatabaseName(), $this->getCollectionName(), $options); diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index f52f1958a..17628e382 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -9,6 +9,7 @@ use MongoDB\Operation\Find; use MongoDB\Operation\MapReduce; use MongoDB\Tests\CommandObserver; + use function is_object; use function iterator_to_array; use function usort; @@ -22,13 +23,13 @@ */ class MapReduceFunctionalTest extends FunctionalTestCase { - public function testDefaultReadConcernIsOmitted() + public function testDefaultReadConcernIsOmitted(): void { // Collection must exist for mapReduce command $this->createCollection(); (new CommandObserver())->observe( - function () { + function (): void { $operation = new MapReduce( $this->getDatabaseName(), $this->getCollectionName(), @@ -40,19 +41,19 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('readConcern', $event['started']->getCommand()); } ); } - public function testDefaultWriteConcernIsOmitted() + public function testDefaultWriteConcernIsOmitted(): void { // Collection must exist for mapReduce command $this->createCollection(); (new CommandObserver())->observe( - function () { + function (): void { $operation = new MapReduce( $this->getDatabaseName(), $this->getCollectionName(), @@ -64,7 +65,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); } ); @@ -73,7 +74,7 @@ function (array $event) { $operation->execute($this->getPrimaryServer()); } - public function testFinalize() + public function testFinalize(): void { $this->createFixtures(3); @@ -88,7 +89,7 @@ public function testFinalize() $this->assertNotNull($result); } - public function testResult() + public function testResult(): void { $this->createFixtures(3); @@ -107,7 +108,7 @@ public function testResult() } } - public function testResultIncludesTimingWithVerboseOption() + public function testResultIncludesTimingWithVerboseOption(): void { if (version_compare($this->getServerVersion(), '4.3.0', '>=')) { $this->markTestSkipped('mapReduce statistics are no longer exposed'); @@ -128,7 +129,7 @@ public function testResultIncludesTimingWithVerboseOption() $this->assertNotEmpty($result->getTiming()); } - public function testResultDoesNotIncludeTimingWithoutVerboseOption() + public function testResultDoesNotIncludeTimingWithoutVerboseOption(): void { if (version_compare($this->getServerVersion(), '4.3.0', '>=')) { $this->markTestSkipped('mapReduce statistics are no longer exposed'); @@ -149,7 +150,7 @@ public function testResultDoesNotIncludeTimingWithoutVerboseOption() $this->assertEmpty($result->getTiming()); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); @@ -158,7 +159,7 @@ public function testSessionOption() $this->createFixtures(3); (new CommandObserver())->observe( - function () { + function (): void { $operation = new MapReduce( $this->getDatabaseName(), $this->getCollectionName(), @@ -170,13 +171,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); @@ -185,7 +186,7 @@ public function testBypassDocumentValidationSetWhenTrue() $this->createFixtures(1); (new CommandObserver())->observe( - function () { + function (): void { $operation = new MapReduce( $this->getDatabaseName(), $this->getCollectionName(), @@ -197,14 +198,14 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); @@ -213,7 +214,7 @@ public function testBypassDocumentValidationUnsetWhenFalse() $this->createFixtures(1); (new CommandObserver())->observe( - function () { + function (): void { $operation = new MapReduce( $this->getDatabaseName(), $this->getCollectionName(), @@ -225,7 +226,7 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); @@ -234,7 +235,7 @@ function (array $event) { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOptionWithInlineResults(array $typeMap = null, array $expectedDocuments) + public function testTypeMapOptionWithInlineResults(?array $typeMap = null, array $expectedDocuments): void { $this->createFixtures(3); @@ -281,7 +282,7 @@ public function provideTypeMapOptionsAndExpectedDocuments() /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOptionWithOutputCollection(array $typeMap = null, array $expectedDocuments) + public function testTypeMapOptionWithOutputCollection(?array $typeMap = null, array $expectedDocuments): void { $this->createFixtures(3); @@ -308,7 +309,7 @@ public function testTypeMapOptionWithOutputCollection(array $typeMap = null, arr * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new BulkWrite(['ordered' => true]); @@ -322,9 +323,9 @@ private function createFixtures($n) $this->assertEquals($n * 2, $result->getInsertedCount()); } - private function sortResults(array $results) : array + private function sortResults(array $results): array { - $sortFunction = static function ($resultA, $resultB) : int { + $sortFunction = static function ($resultA, $resultB): int { $idA = is_object($resultA) ? $resultA->_id : $resultA['_id']; $idB = is_object($resultB) ? $resultB->_id : $resultB['_id']; diff --git a/tests/Operation/MapReduceTest.php b/tests/Operation/MapReduceTest.php index 635dffb06..1376362db 100644 --- a/tests/Operation/MapReduceTest.php +++ b/tests/Operation/MapReduceTest.php @@ -13,7 +13,7 @@ class MapReduceTest extends TestCase /** * @dataProvider provideInvalidOutValues */ - public function testConstructorOutArgumentTypeCheck($out) + public function testConstructorOutArgumentTypeCheck($out): void { $map = new Javascript('function() { emit(this.x, this.y); }'); $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); @@ -30,7 +30,7 @@ public function provideInvalidOutValues() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $map = new Javascript('function() { emit(this.x, this.y); }'); $reduce = new Javascript('function(key, values) { return Array.sum(values); }'); diff --git a/tests/Operation/ModifyCollectionFunctionalTest.php b/tests/Operation/ModifyCollectionFunctionalTest.php index 45f685da3..75f77649a 100644 --- a/tests/Operation/ModifyCollectionFunctionalTest.php +++ b/tests/Operation/ModifyCollectionFunctionalTest.php @@ -4,6 +4,7 @@ use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\ModifyCollection; + use function array_key_exists; class ModifyCollectionFunctionalTest extends FunctionalTestCase @@ -13,7 +14,7 @@ class ModifyCollectionFunctionalTest extends FunctionalTestCase * @group matrix-testing-exclude-server-4.4-driver-4.0-topology-sharded_cluster * @group matrix-testing-exclude-server-5.0-driver-4.0-topology-sharded_cluster */ - public function testCollMod() + public function testCollMod(): void { $this->createCollection(); diff --git a/tests/Operation/ModifyCollectionTest.php b/tests/Operation/ModifyCollectionTest.php index 48a48d39d..2faed3e1f 100644 --- a/tests/Operation/ModifyCollectionTest.php +++ b/tests/Operation/ModifyCollectionTest.php @@ -7,7 +7,7 @@ class ModifyCollectionTest extends TestCase { - public function testConstructorEmptyCollectionOptions() + public function testConstructorEmptyCollectionOptions(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$collectionOptions is empty'); @@ -17,7 +17,7 @@ public function testConstructorEmptyCollectionOptions() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new ModifyCollection($this->getDatabaseName(), $this->getCollectionName(), [], $options); diff --git a/tests/Operation/ReplaceOneTest.php b/tests/Operation/ReplaceOneTest.php index a639e2252..21b6a396c 100644 --- a/tests/Operation/ReplaceOneTest.php +++ b/tests/Operation/ReplaceOneTest.php @@ -11,7 +11,7 @@ class ReplaceOneTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), $filter, ['y' => 1]); @@ -20,7 +20,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorReplacementArgumentTypeCheck($replacement) + public function testConstructorReplacementArgumentTypeCheck($replacement): void { $this->expectException(InvalidArgumentException::class); new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); @@ -30,7 +30,7 @@ public function testConstructorReplacementArgumentTypeCheck($replacement) * @dataProvider provideReplacementDocuments * @doesNotPerformAssertions */ - public function testConstructorReplacementArgument($replacement) + public function testConstructorReplacementArgument($replacement): void { new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement); } @@ -38,7 +38,7 @@ public function testConstructorReplacementArgument($replacement) /** * @dataProvider provideUpdateDocuments */ - public function testConstructorReplacementArgumentRequiresNoOperators($replacement) + public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('First key in $replacement argument is an update operator'); diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php index 9b6ccbc9b..89373400b 100644 --- a/tests/Operation/UpdateFunctionalTest.php +++ b/tests/Operation/UpdateFunctionalTest.php @@ -10,6 +10,7 @@ use MongoDB\Operation\Update; use MongoDB\Tests\CommandObserver; use MongoDB\UpdateResult; + use function version_compare; class UpdateFunctionalTest extends FunctionalTestCase @@ -17,21 +18,21 @@ class UpdateFunctionalTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName()); } - public function testSessionOption() + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Sessions are not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Update( $this->getDatabaseName(), $this->getCollectionName(), @@ -42,20 +43,20 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); } ); } - public function testBypassDocumentValidationSetWhenTrue() + public function testBypassDocumentValidationSetWhenTrue(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Update( $this->getDatabaseName(), $this->getCollectionName(), @@ -66,21 +67,21 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); $this->assertEquals(true, $event['started']->getCommand()->bypassDocumentValidation); } ); } - public function testBypassDocumentValidationUnsetWhenFalse() + public function testBypassDocumentValidationUnsetWhenFalse(): void { if (version_compare($this->getServerVersion(), '3.2.0', '<')) { $this->markTestSkipped('bypassDocumentValidation is not supported'); } (new CommandObserver())->observe( - function () { + function (): void { $operation = new Update( $this->getDatabaseName(), $this->getCollectionName(), @@ -91,13 +92,13 @@ function () { $operation->execute($this->getPrimaryServer()); }, - function (array $event) { + function (array $event): void { $this->assertObjectNotHasAttribute('bypassDocumentValidation', $event['started']->getCommand()); } ); } - public function testUpdateOne() + public function testUpdateOne(): void { $this->createFixtures(3); @@ -122,7 +123,7 @@ public function testUpdateOne() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testUpdateMany() + public function testUpdateMany(): void { $this->createFixtures(3); @@ -148,7 +149,7 @@ public function testUpdateMany() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testUpdateManyWithExistingId() + public function testUpdateManyWithExistingId(): void { $this->createFixtures(3); @@ -175,7 +176,7 @@ public function testUpdateManyWithExistingId() $this->assertSameDocuments($expected, $this->collection->find()); } - public function testUpdateManyWithGeneratedId() + public function testUpdateManyWithGeneratedId(): void { $this->createFixtures(3); @@ -218,7 +219,7 @@ public function testUnacknowledgedWriteConcern() /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesMatchedCount(UpdateResult $result) + public function testUnacknowledgedWriteConcernAccessesMatchedCount(UpdateResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -228,7 +229,7 @@ public function testUnacknowledgedWriteConcernAccessesMatchedCount(UpdateResult /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesModifiedCount(UpdateResult $result) + public function testUnacknowledgedWriteConcernAccessesModifiedCount(UpdateResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -238,7 +239,7 @@ public function testUnacknowledgedWriteConcernAccessesModifiedCount(UpdateResult /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesUpsertedCount(UpdateResult $result) + public function testUnacknowledgedWriteConcernAccessesUpsertedCount(UpdateResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -248,7 +249,7 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedCount(UpdateResult /** * @depends testUnacknowledgedWriteConcern */ - public function testUnacknowledgedWriteConcernAccessesUpsertedId(UpdateResult $result) + public function testUnacknowledgedWriteConcernAccessesUpsertedId(UpdateResult $result): void { $this->expectException(BadMethodCallException::class); $this->expectExceptionMessageMatches('/[\w:\\\\]+ should not be called for an unacknowledged write result/'); @@ -260,7 +261,7 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedId(UpdateResult $r * * @param integer $n */ - private function createFixtures($n) + private function createFixtures(int $n): void { $bulkWrite = new BulkWrite(['ordered' => true]); diff --git a/tests/Operation/UpdateManyTest.php b/tests/Operation/UpdateManyTest.php index 70537c0bc..cf1d770a6 100644 --- a/tests/Operation/UpdateManyTest.php +++ b/tests/Operation/UpdateManyTest.php @@ -11,7 +11,7 @@ class UpdateManyTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]); @@ -20,7 +20,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorUpdateArgumentTypeCheck($update) + public function testConstructorUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); @@ -30,7 +30,7 @@ public function testConstructorUpdateArgumentTypeCheck($update) * @dataProvider provideUpdateDocuments * @doesNotPerformAssertions */ - public function testConstructorUpdateArgument($update) + public function testConstructorUpdateArgument($update): void { new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); } @@ -38,7 +38,7 @@ public function testConstructorUpdateArgument($update) /** * @dataProvider provideReplacementDocuments */ - public function testConstructorUpdateArgumentRequiresOperators($replacement) + public function testConstructorUpdateArgumentRequiresOperators($replacement): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline'); diff --git a/tests/Operation/UpdateOneTest.php b/tests/Operation/UpdateOneTest.php index 6aec7a5ba..9933692d8 100644 --- a/tests/Operation/UpdateOneTest.php +++ b/tests/Operation/UpdateOneTest.php @@ -11,7 +11,7 @@ class UpdateOneTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]); @@ -20,7 +20,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorUpdateArgumentTypeCheck($update) + public function testConstructorUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); @@ -30,7 +30,7 @@ public function testConstructorUpdateArgumentTypeCheck($update) * @dataProvider provideUpdateDocuments * @doesNotPerformAssertions */ - public function testConstructorUpdateArgument($update) + public function testConstructorUpdateArgument($update): void { new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update); } @@ -38,7 +38,7 @@ public function testConstructorUpdateArgument($update) /** * @dataProvider provideReplacementDocuments */ - public function testConstructorUpdateArgumentRequiresOperators($replacement) + public function testConstructorUpdateArgumentRequiresOperators($replacement): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline'); diff --git a/tests/Operation/UpdateTest.php b/tests/Operation/UpdateTest.php index ddb61a175..2e3773d34 100644 --- a/tests/Operation/UpdateTest.php +++ b/tests/Operation/UpdateTest.php @@ -10,7 +10,7 @@ class UpdateTest extends TestCase /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorFilterArgumentTypeCheck($filter) + public function testConstructorFilterArgumentTypeCheck($filter): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$filter to have type "array or object" but found "[\w ]+"/'); @@ -20,7 +20,7 @@ public function testConstructorFilterArgumentTypeCheck($filter) /** * @dataProvider provideInvalidDocumentValues */ - public function testConstructorUpdateArgumentTypeCheck($update) + public function testConstructorUpdateArgumentTypeCheck($update): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Expected \$update to have type "array or object" but found "[\w ]+"/'); @@ -30,7 +30,7 @@ public function testConstructorUpdateArgumentTypeCheck($update) /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], ['y' => 1], $options); diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index 45716f90e..2d64cf568 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -21,8 +21,10 @@ use PHPUnit\Framework\ExpectationFailedException; use ReflectionClass; use stdClass; + use function array_diff_key; use function array_map; +use function assert; use function bin2hex; use function microtime; use function MongoDB\server_supports_feature; @@ -36,8 +38,8 @@ */ class WatchFunctionalTest extends FunctionalTestCase { - const INTERRUPTED = 11601; - const NOT_PRIMARY = 10107; + public const INTERRUPTED = 11601; + public const NOT_PRIMARY = 10107; /** @var integer */ private static $wireVersionForStartAtOperationTime = 7; @@ -45,7 +47,7 @@ class WatchFunctionalTest extends FunctionalTestCase /** @var array */ private $defaultOptions = ['maxAwaitTimeMS' => 500]; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -57,7 +59,7 @@ public function setUp() : void * Prose test 1: "ChangeStream must continuously track the last seen * resumeToken" */ - public function testGetResumeToken() + public function testGetResumeToken(): void { if ($this->isPostBatchResumeTokenSupported()) { $this->markTestSkipped('postBatchResumeToken is supported'); @@ -104,7 +106,7 @@ public function testGetResumeToken() * Expected result: getResumeToken must return the _id of the previous * document returned. */ - public function testGetResumeTokenWithPostBatchResumeToken() + public function testGetResumeTokenWithPostBatchResumeToken(): void { if (! $this->isPostBatchResumeTokenSupported()) { $this->markTestSkipped('postBatchResumeToken is not supported'); @@ -115,10 +117,10 @@ public function testGetResumeTokenWithPostBatchResumeToken() $events = []; (new CommandObserver())->observe( - function () use ($operation, &$changeStream) { + function () use ($operation, &$changeStream): void { $changeStream = $operation->execute($this->getPrimaryServer()); }, - function (array $event) use (&$events) { + function (array $event) use (&$events): void { $events[] = $event; } ); @@ -137,10 +139,10 @@ function (array $event) use (&$events) { $lastEvent = null; (new CommandObserver())->observe( - function () use ($changeStream) { + function () use ($changeStream): void { $this->advanceCursorUntilValid($changeStream); }, - function (array $event) use (&$lastEvent) { + function (array $event) use (&$lastEvent): void { $lastEvent = $event; } ); @@ -155,7 +157,7 @@ function (array $event) use (&$lastEvent) { $this->assertSameDocument($postBatchResumeToken, $changeStream->getResumeToken()); } - public function testNextResumesAfterConnectionException() + public function testNextResumesAfterConnectionException(): void { $this->skipIfIsShardedCluster('initial aggregate command times out due to socketTimeoutMS'); @@ -172,10 +174,10 @@ public function testNextResumesAfterConnectionException() $commands = []; (new CommandObserver())->observe( - function () use ($changeStream) { + function () use ($changeStream): void { $changeStream->next(); }, - function (array $event) use (&$commands) { + function (array $event) use (&$commands): void { $commands[] = $event['started']->getCommandName(); } ); @@ -202,7 +204,7 @@ function (array $event) use (&$commands) { $this->assertSame($expectedCommands, $commands); } - public function testResumeBeforeReceivingAnyResultsIncludesPostBatchResumeToken() + public function testResumeBeforeReceivingAnyResultsIncludesPostBatchResumeToken(): void { if (! $this->isPostBatchResumeTokenSupported()) { $this->markTestSkipped('postBatchResumeToken is not supported'); @@ -213,10 +215,10 @@ public function testResumeBeforeReceivingAnyResultsIncludesPostBatchResumeToken( $events = []; (new CommandObserver())->observe( - function () use ($operation, &$changeStream) { + function () use ($operation, &$changeStream): void { $changeStream = $operation->execute($this->getPrimaryServer()); }, - function (array $event) use (&$events) { + function (array $event) use (&$events): void { $events[] = $event; } ); @@ -228,17 +230,17 @@ function (array $event) use (&$events) { $this->assertFalse($changeStream->valid()); $this->forceChangeStreamResume(); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $events = []; (new CommandObserver())->observe( - function () use ($changeStream) { + function () use ($changeStream): void { $changeStream->next(); }, - function (array $event) use (&$events) { + function (array $event) use (&$events): void { $events[] = $event; } ); @@ -259,7 +261,7 @@ function (array $event) use (&$events) { $this->assertFalse($changeStream->valid()); } - private function assertResumeAfter($expectedResumeToken, stdClass $command) + private function assertResumeAfter($expectedResumeToken, stdClass $command): void { $this->assertObjectHasAttribute('pipeline', $command); $this->assertIsArray($command->pipeline); @@ -274,7 +276,7 @@ private function assertResumeAfter($expectedResumeToken, stdClass $command) * >=4.0 and <4.0.7 that has not received any results yet MUST include a * startAtOperationTime option when resuming a changestream." */ - public function testResumeBeforeReceivingAnyResultsIncludesStartAtOperationTime() + public function testResumeBeforeReceivingAnyResultsIncludesStartAtOperationTime(): void { if (! $this->isStartAtOperationTimeSupported()) { $this->markTestSkipped('startAtOperationTime is not supported'); @@ -289,10 +291,10 @@ public function testResumeBeforeReceivingAnyResultsIncludesStartAtOperationTime( $events = []; (new CommandObserver())->observe( - function () use ($operation, &$changeStream) { + function () use ($operation, &$changeStream): void { $changeStream = $operation->execute($this->getPrimaryServer()); }, - function (array $event) use (&$events) { + function (array $event) use (&$events): void { $events[] = $event; } ); @@ -307,17 +309,17 @@ function (array $event) use (&$events) { $this->assertFalse($changeStream->valid()); $this->forceChangeStreamResume(); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $events = []; (new CommandObserver())->observe( - function () use ($changeStream) { + function () use ($changeStream): void { $changeStream->next(); }, - function (array $event) use (&$events) { + function (array $event) use (&$events): void { $events[] = $event; } ); @@ -338,7 +340,7 @@ function (array $event) use (&$events) { $this->assertFalse($changeStream->valid()); } - private function assertStartAtOperationTime(TimestampInterface $expectedOperationTime, stdClass $command) + private function assertStartAtOperationTime(TimestampInterface $expectedOperationTime, stdClass $command): void { $this->assertObjectHasAttribute('pipeline', $command); $this->assertIsArray($command->pipeline); @@ -348,7 +350,7 @@ private function assertStartAtOperationTime(TimestampInterface $expectedOperatio $this->assertEquals($expectedOperationTime, $command->pipeline[0]->{'$changeStream'}->startAtOperationTime); } - public function testRewindMultipleTimesWithResults() + public function testRewindMultipleTimesWithResults(): void { $this->skipIfIsShardedCluster('Cursor needs to be advanced multiple times and can\'t be rewound afterwards.'); @@ -358,7 +360,7 @@ public function testRewindMultipleTimesWithResults() $this->insertDocument(['x' => 1]); $this->insertDocument(['x' => 2]); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -366,7 +368,7 @@ public function testRewindMultipleTimesWithResults() $this->assertNull($changeStream->current()); // Subsequent rewind does not change iterator state - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -380,7 +382,7 @@ public function testRewindMultipleTimesWithResults() /* Rewinding when the iterator is still at its first element is a NOP. * Note: PHPLIB-448 may see rewind() throw after any call to next() */ - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertTrue($changeStream->valid()); @@ -397,12 +399,12 @@ public function testRewindMultipleTimesWithResults() $changeStream->rewind(); } - public function testRewindMultipleTimesWithNoResults() + public function testRewindMultipleTimesWithNoResults(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -410,7 +412,7 @@ public function testRewindMultipleTimesWithNoResults() $this->assertNull($changeStream->current()); // Subsequent rewind does not change iterator state - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -424,7 +426,7 @@ public function testRewindMultipleTimesWithNoResults() /* Rewinding when the iterator hasn't advanced to an element is a NOP. * Note: PHPLIB-448 may see rewind() throw after any call to next() */ - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -432,12 +434,12 @@ public function testRewindMultipleTimesWithNoResults() $this->assertNull($changeStream->current()); } - public function testNoChangeAfterResumeBeforeInsert() + public function testNoChangeAfterResumeBeforeInsert(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -476,7 +478,7 @@ public function testNoChangeAfterResumeBeforeInsert() $this->assertMatchesDocument($expectedResult, $changeStream->current()); } - public function testResumeMultipleTimesInSuccession() + public function testResumeMultipleTimesInSuccession(): void { $this->skipIfIsShardedCluster('getMore may return empty response before periodicNoopIntervalSecs on sharded clusters.'); @@ -488,7 +490,7 @@ public function testResumeMultipleTimesInSuccession() * key. */ $this->forceChangeStreamResume(); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -556,7 +558,7 @@ public function testResumeMultipleTimesInSuccession() $this->insertDocument(['_id' => 3]); $this->forceChangeStreamResume(); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertTrue($changeStream->valid()); @@ -597,7 +599,7 @@ public function testResumeMultipleTimesInSuccession() $this->assertMatchesDocument($expectedResult, $changeStream->current()); } - public function testKey() + public function testKey(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -605,7 +607,7 @@ public function testKey() $this->assertFalse($changeStream->valid()); $this->assertNull($changeStream->key()); - $this->assertNoCommandExecuted(function () use ($changeStream) { + $this->assertNoCommandExecuted(function () use ($changeStream): void { $changeStream->rewind(); }); $this->assertFalse($changeStream->valid()); @@ -636,7 +638,7 @@ public function testKey() $this->assertSame(1, $changeStream->key()); } - public function testNonEmptyPipeline() + public function testNonEmptyPipeline(): void { $pipeline = [['$project' => ['foo' => [0]]]]; @@ -663,7 +665,7 @@ public function testNonEmptyPipeline() * with a cursor id and an initial empty batch is not closed on the driver * side." */ - public function testInitialCursorIsNotClosed() + public function testInitialCursorIsNotClosed(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), []); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -695,13 +697,13 @@ public function testInitialCursorIsNotClosed() * response is missing the resume token (if wire version is < 8, this is a * driver-side error; for 8+, this is a server-side error)" */ - public function testResumeTokenNotFoundClientSideError() + public function testResumeTokenNotFoundClientSideError(): void { if (version_compare($this->getServerVersion(), '4.1.8', '>=')) { $this->markTestSkipped('Server rejects change streams that modify resume token (SERVER-37786)'); } - $pipeline = [['$project' => ['_id' => 0 ]]]; + $pipeline = [['$project' => ['_id' => 0]]]; $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $pipeline, $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -723,13 +725,13 @@ public function testResumeTokenNotFoundClientSideError() * response is missing the resume token (if wire version is < 8, this is a * driver-side error; for 8+, this is a server-side error)" */ - public function testResumeTokenNotFoundServerSideError() + public function testResumeTokenNotFoundServerSideError(): void { if (version_compare($this->getServerVersion(), '4.1.8', '<')) { $this->markTestSkipped('Server does not reject change streams that modify resume token'); } - $pipeline = [['$project' => ['_id' => 0 ]]]; + $pipeline = [['$project' => ['_id' => 0]]]; $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $pipeline, $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -746,7 +748,7 @@ public function testResumeTokenNotFoundServerSideError() * response is missing the resume token (if wire version is < 8, this is a * driver-side error; for 8+, this is a server-side error)" */ - public function testResumeTokenInvalidTypeClientSideError() + public function testResumeTokenInvalidTypeClientSideError(): void { if (version_compare($this->getServerVersion(), '4.1.8', '>=')) { $this->markTestSkipped('Server rejects change streams that modify resume token (SERVER-37786)'); @@ -774,7 +776,7 @@ public function testResumeTokenInvalidTypeClientSideError() * response is missing the resume token (if wire version is < 8, this is a * driver-side error; for 8+, this is a server-side error)" */ - public function testResumeTokenInvalidTypeServerSideError() + public function testResumeTokenInvalidTypeServerSideError(): void { if (version_compare($this->getServerVersion(), '4.1.8', '<')) { $this->markTestSkipped('Server does not reject change streams that modify resume token'); @@ -792,7 +794,7 @@ public function testResumeTokenInvalidTypeServerSideError() $this->advanceCursorUntilValid($changeStream); } - public function testMaxAwaitTimeMS() + public function testMaxAwaitTimeMS(): void { /* On average, an acknowledged write takes about 20 ms to appear in a * change stream on the server so we'll use a higher maxAwaitTimeMS to @@ -858,7 +860,7 @@ public function testMaxAwaitTimeMS() } } - public function testRewindExtractsResumeTokenAndNextResumes() + public function testRewindExtractsResumeTokenAndNextResumes(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -918,7 +920,7 @@ public function testRewindExtractsResumeTokenAndNextResumes() $this->assertMatchesDocument($expectedResult, $changeStream->current()); } - public function testResumeAfterOption() + public function testResumeAfterOption(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -960,7 +962,7 @@ public function testResumeAfterOption() $this->assertMatchesDocument($expectedResult, $changeStream->current()); } - public function testStartAfterOption() + public function testStartAfterOption(): void { if (version_compare($this->getServerVersion(), '4.1.1', '<')) { $this->markTestSkipped('startAfter is not supported'); @@ -1009,7 +1011,7 @@ public function testStartAfterOption() /** * @dataProvider provideTypeMapOptionsAndExpectedChangeDocument */ - public function testTypeMapOption(array $typeMap, $expectedChangeDocument) + public function testTypeMapOption(array $typeMap, $expectedChangeDocument): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], ['typeMap' => $typeMap] + $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -1058,7 +1060,7 @@ public function provideTypeMapOptionsAndExpectedChangeDocument() ]; } - public function testNextAdvancesKey() + public function testNextAdvancesKey(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -1077,9 +1079,9 @@ public function testNextAdvancesKey() $this->assertSame(1, $changeStream->key()); } - public function testResumeTokenNotFoundDoesNotAdvanceKey() + public function testResumeTokenNotFoundDoesNotAdvanceKey(): void { - $pipeline = [['$project' => ['_id' => 0 ]]]; + $pipeline = [['$project' => ['_id' => 0]]]; $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $pipeline, $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -1115,7 +1117,7 @@ public function testResumeTokenNotFoundDoesNotAdvanceKey() $this->assertNull($changeStream->key()); } - public function testSessionPersistsAfterResume() + public function testSessionPersistsAfterResume(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); @@ -1130,10 +1132,10 @@ public function testSessionPersistsAfterResume() * aggregate matches the lsid of any subsequent aggregates and getMores. */ (new CommandObserver())->observe( - function () use ($operation, &$changeStream) { + function () use ($operation, &$changeStream): void { $changeStream = $operation->execute($this->getPrimaryServer()); }, - function (array $event) use (&$originalSession) { + function (array $event) use (&$originalSession): void { $command = $event['started']->getCommand(); if (isset($command->aggregate)) { $originalSession = bin2hex((string) $command->lsid->id); @@ -1145,10 +1147,10 @@ function (array $event) use (&$originalSession) { $this->forceChangeStreamResume(); (new CommandObserver())->observe( - function () use (&$changeStream) { + function () use (&$changeStream): void { $changeStream->next(); }, - function (array $event) use (&$sessionAfterResume, &$commands) { + function (array $event) use (&$sessionAfterResume, &$commands): void { $commands[] = $event['started']->getCommandName(); $sessionAfterResume[] = bin2hex((string) $event['started']->getCommand()->lsid->id); } @@ -1174,7 +1176,7 @@ function (array $event) use (&$sessionAfterResume, &$commands) { } } - public function testSessionFreed() + public function testSessionFreed(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); @@ -1198,7 +1200,7 @@ public function testSessionFreed() * resumable error (including not primary) with the initial pipeline and * options, except for the addition/update of a resumeToken." */ - public function testResumeRepeatsOriginalPipelineAndOptions() + public function testResumeRepeatsOriginalPipelineAndOptions(): void { $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); @@ -1215,14 +1217,14 @@ public function testResumeRepeatsOriginalPipelineAndOptions() ]); (new CommandObserver())->observe( - function () use ($operation) { + function () use ($operation): void { $changeStream = $operation->execute($this->getPrimaryServer()); // The first next will hit the fail point, causing a resume $changeStream->next(); $changeStream->next(); }, - function (array $event) use (&$aggregateCommands) { + function (array $event) use (&$aggregateCommands): void { $command = $event['started']->getCommand(); if ($event['started']->getCommandName() !== 'aggregate') { return; @@ -1278,7 +1280,7 @@ function (array $aggregateCommand) { * Prose test 4: "ChangeStream will not attempt to resume on any error * encountered while executing an aggregate command." */ - public function testErrorDuringAggregateCommandDoesNotCauseResume() + public function testErrorDuringAggregateCommandDoesNotCauseResume(): void { if (version_compare($this->getServerVersion(), '4.0.0', '<')) { $this->markTestSkipped('failCommand is not supported'); @@ -1297,10 +1299,10 @@ public function testErrorDuringAggregateCommandDoesNotCauseResume() $this->expectException(CommandException::class); (new CommandObserver())->observe( - function () use ($operation) { + function () use ($operation): void { $operation->execute($this->getPrimaryServer()); }, - function (array $event) use (&$commandCount) { + function (array $event) use (&$commandCount): void { $commandCount++; } ); @@ -1312,7 +1314,7 @@ function (array $event) use (&$commandCount) { * Prose test 6: "ChangeStream will perform server selection before * attempting to resume, using initial readPreference" */ - public function testOriginalReadPreferenceIsPreservedOnResume() + public function testOriginalReadPreferenceIsPreservedOnResume(): void { if ($this->isShardedCluster()) { $this->markTestSkipped('Test does not apply to sharded clusters'); @@ -1342,8 +1344,8 @@ function () { $changeStream, ChangeStream::class ); - /** @var Cursor $cursor */ $cursor = $getCursor(); + assert($cursor instanceof Cursor); self::assertTrue($cursor->getServer()->isSecondary()); } @@ -1357,7 +1359,7 @@ function () { * - getResumeToken must return resumeAfter from the initial aggregate if the option was specified. * - If resumeAfter was not specified, the getResumeToken result must be empty. */ - public function testGetResumeTokenReturnsOriginalResumeTokenOnEmptyBatch() + public function testGetResumeTokenReturnsOriginalResumeTokenOnEmptyBatch(): void { if ($this->isPostBatchResumeTokenSupported()) { $this->markTestSkipped('postBatchResumeToken is supported'); @@ -1393,7 +1395,7 @@ public function testGetResumeTokenReturnsOriginalResumeTokenOnEmptyBatch() * - getResumeToken must return resumeAfter from the initial aggregate if the option was specified. * - If neither the startAfter nor resumeAfter options were specified, the getResumeToken result must be empty. */ - public function testResumeTokenBehaviour() + public function testResumeTokenBehaviour(): void { if (version_compare($this->getServerVersion(), '4.1.1', '<')) { $this->markTestSkipped('Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1'); @@ -1406,9 +1408,9 @@ public function testResumeTokenBehaviour() $lastOpTime = null; $changeStream = null; - (new CommandObserver())->observe(function () use ($operation, &$changeStream) { + (new CommandObserver())->observe(function () use ($operation, &$changeStream): void { $changeStream = $operation->execute($this->getPrimaryServer()); - }, function ($event) use (&$lastOpTime) { + }, function ($event) use (&$lastOpTime): void { $this->assertInstanceOf(CommandSucceededEvent::class, $event['succeeded']); $reply = $event['succeeded']->getReply(); @@ -1452,7 +1454,7 @@ public function testResumeTokenBehaviour() * MUST include a startAfter option and MUST NOT include a resumeAfter * option when resuming a change stream." */ - public function testResumingChangeStreamWithoutPreviousResultsIncludesStartAfterOption() + public function testResumingChangeStreamWithoutPreviousResultsIncludesStartAfterOption(): void { if (version_compare($this->getServerVersion(), '4.1.1', '<')) { $this->markTestSkipped('Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1'); @@ -1476,10 +1478,10 @@ public function testResumingChangeStreamWithoutPreviousResultsIncludesStartAfter $aggregateCommand = null; (new CommandObserver())->observe( - function () use ($changeStream) { + function () use ($changeStream): void { $changeStream->next(); }, - function (array $event) use (&$aggregateCommand) { + function (array $event) use (&$aggregateCommand): void { if ($event['started']->getCommandName() !== 'aggregate') { return; } @@ -1499,7 +1501,7 @@ function (array $event) use (&$aggregateCommand) { * MUST include a resumeAfter option and MUST NOT include a startAfter * option when resuming a change stream." */ - public function testResumingChangeStreamWithPreviousResultsIncludesResumeAfterOption() + public function testResumingChangeStreamWithPreviousResultsIncludesResumeAfterOption(): void { if (version_compare($this->getServerVersion(), '4.1.1', '<')) { $this->markTestSkipped('Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1'); @@ -1527,10 +1529,10 @@ public function testResumingChangeStreamWithPreviousResultsIncludesResumeAfterOp $aggregateCommand = null; (new CommandObserver())->observe( - function () use ($changeStream) { + function () use ($changeStream): void { $changeStream->next(); }, - function (array $event) use (&$aggregateCommand) { + function (array $event) use (&$aggregateCommand): void { if ($event['started']->getCommandName() !== 'aggregate') { return; } @@ -1544,13 +1546,13 @@ function (array $event) use (&$aggregateCommand) { $this->assertObjectHasAttribute('resumeAfter', $aggregateCommand->pipeline[0]->{'$changeStream'}); } - private function assertNoCommandExecuted(callable $callable) + private function assertNoCommandExecuted(callable $callable): void { $commands = []; (new CommandObserver())->observe( $callable, - function (array $event) use (&$commands) { + function (array $event) use (&$commands): void { $this->fail(sprintf('"%s" command was executed', $event['started']->getCommandName())); } ); @@ -1558,7 +1560,7 @@ function (array $event) use (&$commands) { $this->assertEmpty($commands); } - private function forceChangeStreamResume() + private function forceChangeStreamResume(): void { $this->configureFailPoint([ 'configureFailPoint' => 'failCommand', @@ -1581,7 +1583,7 @@ private function getPostBatchResumeTokenFromReply(stdClass $reply) return $reply->cursor->postBatchResumeToken; } - private function insertDocument($document) + private function insertDocument($document): void { $insertOne = new InsertOne( $this->getDatabaseName(), @@ -1603,7 +1605,7 @@ private function isStartAtOperationTimeSupported() return server_supports_feature($this->getPrimaryServer(), self::$wireVersionForStartAtOperationTime); } - private function advanceCursorUntilValid(Iterator $iterator, $limitOnShardedClusters = 10) + private function advanceCursorUntilValid(Iterator $iterator, $limitOnShardedClusters = 10): void { if (! $this->isShardedCluster()) { $iterator->next(); @@ -1622,7 +1624,7 @@ private function advanceCursorUntilValid(Iterator $iterator, $limitOnShardedClus throw new ExpectationFailedException(sprintf('Expected cursor to return an element but none was found after %d attempts.', $limitOnShardedClusters)); } - private function skipIfIsShardedCluster($message) + private function skipIfIsShardedCluster($message): void { if (! $this->isShardedCluster()) { return; diff --git a/tests/Operation/WatchTest.php b/tests/Operation/WatchTest.php index 8cf94254a..ba790fb5f 100644 --- a/tests/Operation/WatchTest.php +++ b/tests/Operation/WatchTest.php @@ -12,7 +12,7 @@ */ class WatchTest extends FunctionalTestCase { - public function testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull() + public function testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$collectionName should also be null if $databaseName is null'); @@ -20,7 +20,7 @@ public function testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull() new Watch($this->manager, null, 'foo', []); } - public function testConstructorPipelineArgumentMustBeAList() + public function testConstructorPipelineArgumentMustBeAList(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('$pipeline is not a list (unexpected index: "foo")'); @@ -34,7 +34,7 @@ public function testConstructorPipelineArgumentMustBeAList() /** * @dataProvider provideInvalidConstructorOptions */ - public function testConstructorOptionTypeChecks(array $options) + public function testConstructorOptionTypeChecks(array $options): void { $this->expectException(InvalidArgumentException::class); new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $options); diff --git a/tests/PHPUnit/Functions.php b/tests/PHPUnit/Functions.php index 5d983e893..6f9bf5dee 100644 --- a/tests/PHPUnit/Functions.php +++ b/tests/PHPUnit/Functions.php @@ -1,4 +1,5 @@ - $expected * @psalm-assert ExpectedType $actual */ - function assertInstanceOf(string $expected, $actual, string $message = '') + function assertInstanceOf(string $expected, $actual, string $message = ''): void { Assert::assertInstanceOf(...func_get_args()); } @@ -1348,7 +1351,7 @@ function assertInstanceOf(string $expected, $actual, string $message = '') * @psalm-param class-string $expected * @psalm-assert !ExpectedType $actual */ - function assertNotInstanceOf(string $expected, $actual, string $message = '') + function assertNotInstanceOf(string $expected, $actual, string $message = ''): void { Assert::assertNotInstanceOf(...func_get_args()); } @@ -1365,7 +1368,7 @@ function assertNotInstanceOf(string $expected, $actual, string $message = '') * * @psalm-assert array $actual */ - function assertIsArray($actual, string $message = '') + function assertIsArray($actual, string $message = ''): void { Assert::assertIsArray(...func_get_args()); } @@ -1382,7 +1385,7 @@ function assertIsArray($actual, string $message = '') * * @psalm-assert bool $actual */ - function assertIsBool($actual, string $message = '') + function assertIsBool($actual, string $message = ''): void { Assert::assertIsBool(...func_get_args()); } @@ -1399,7 +1402,7 @@ function assertIsBool($actual, string $message = '') * * @psalm-assert float $actual */ - function assertIsFloat($actual, string $message = '') + function assertIsFloat($actual, string $message = ''): void { Assert::assertIsFloat(...func_get_args()); } @@ -1416,7 +1419,7 @@ function assertIsFloat($actual, string $message = '') * * @psalm-assert int $actual */ - function assertIsInt($actual, string $message = '') + function assertIsInt($actual, string $message = ''): void { Assert::assertIsInt(...func_get_args()); } @@ -1433,7 +1436,7 @@ function assertIsInt($actual, string $message = '') * * @psalm-assert numeric $actual */ - function assertIsNumeric($actual, string $message = '') + function assertIsNumeric($actual, string $message = ''): void { Assert::assertIsNumeric(...func_get_args()); } @@ -1450,7 +1453,7 @@ function assertIsNumeric($actual, string $message = '') * * @psalm-assert object $actual */ - function assertIsObject($actual, string $message = '') + function assertIsObject($actual, string $message = ''): void { Assert::assertIsObject(...func_get_args()); } @@ -1467,7 +1470,7 @@ function assertIsObject($actual, string $message = '') * * @psalm-assert resource $actual */ - function assertIsResource($actual, string $message = '') + function assertIsResource($actual, string $message = ''): void { Assert::assertIsResource(...func_get_args()); } @@ -1484,7 +1487,7 @@ function assertIsResource($actual, string $message = '') * * @psalm-assert resource $actual */ - function assertIsClosedResource($actual, string $message = '') + function assertIsClosedResource($actual, string $message = ''): void { Assert::assertIsClosedResource(...func_get_args()); } @@ -1501,7 +1504,7 @@ function assertIsClosedResource($actual, string $message = '') * * @psalm-assert string $actual */ - function assertIsString($actual, string $message = '') + function assertIsString($actual, string $message = ''): void { Assert::assertIsString(...func_get_args()); } @@ -1518,7 +1521,7 @@ function assertIsString($actual, string $message = '') * * @psalm-assert scalar $actual */ - function assertIsScalar($actual, string $message = '') + function assertIsScalar($actual, string $message = ''): void { Assert::assertIsScalar(...func_get_args()); } @@ -1535,7 +1538,7 @@ function assertIsScalar($actual, string $message = '') * * @psalm-assert callable $actual */ - function assertIsCallable($actual, string $message = '') + function assertIsCallable($actual, string $message = ''): void { Assert::assertIsCallable(...func_get_args()); } @@ -1552,7 +1555,7 @@ function assertIsCallable($actual, string $message = '') * * @psalm-assert iterable $actual */ - function assertIsIterable($actual, string $message = '') + function assertIsIterable($actual, string $message = ''): void { Assert::assertIsIterable(...func_get_args()); } @@ -1569,7 +1572,7 @@ function assertIsIterable($actual, string $message = '') * * @psalm-assert !array $actual */ - function assertIsNotArray($actual, string $message = '') + function assertIsNotArray($actual, string $message = ''): void { Assert::assertIsNotArray(...func_get_args()); } @@ -1586,7 +1589,7 @@ function assertIsNotArray($actual, string $message = '') * * @psalm-assert !bool $actual */ - function assertIsNotBool($actual, string $message = '') + function assertIsNotBool($actual, string $message = ''): void { Assert::assertIsNotBool(...func_get_args()); } @@ -1603,7 +1606,7 @@ function assertIsNotBool($actual, string $message = '') * * @psalm-assert !float $actual */ - function assertIsNotFloat($actual, string $message = '') + function assertIsNotFloat($actual, string $message = ''): void { Assert::assertIsNotFloat(...func_get_args()); } @@ -1620,7 +1623,7 @@ function assertIsNotFloat($actual, string $message = '') * * @psalm-assert !int $actual */ - function assertIsNotInt($actual, string $message = '') + function assertIsNotInt($actual, string $message = ''): void { Assert::assertIsNotInt(...func_get_args()); } @@ -1637,7 +1640,7 @@ function assertIsNotInt($actual, string $message = '') * * @psalm-assert !numeric $actual */ - function assertIsNotNumeric($actual, string $message = '') + function assertIsNotNumeric($actual, string $message = ''): void { Assert::assertIsNotNumeric(...func_get_args()); } @@ -1654,7 +1657,7 @@ function assertIsNotNumeric($actual, string $message = '') * * @psalm-assert !object $actual */ - function assertIsNotObject($actual, string $message = '') + function assertIsNotObject($actual, string $message = ''): void { Assert::assertIsNotObject(...func_get_args()); } @@ -1671,7 +1674,7 @@ function assertIsNotObject($actual, string $message = '') * * @psalm-assert !resource $actual */ - function assertIsNotResource($actual, string $message = '') + function assertIsNotResource($actual, string $message = ''): void { Assert::assertIsNotResource(...func_get_args()); } @@ -1688,7 +1691,7 @@ function assertIsNotResource($actual, string $message = '') * * @psalm-assert !resource $actual */ - function assertIsNotClosedResource($actual, string $message = '') + function assertIsNotClosedResource($actual, string $message = ''): void { Assert::assertIsNotClosedResource(...func_get_args()); } @@ -1705,7 +1708,7 @@ function assertIsNotClosedResource($actual, string $message = '') * * @psalm-assert !string $actual */ - function assertIsNotString($actual, string $message = '') + function assertIsNotString($actual, string $message = ''): void { Assert::assertIsNotString(...func_get_args()); } @@ -1722,7 +1725,7 @@ function assertIsNotString($actual, string $message = '') * * @psalm-assert !scalar $actual */ - function assertIsNotScalar($actual, string $message = '') + function assertIsNotScalar($actual, string $message = ''): void { Assert::assertIsNotScalar(...func_get_args()); } @@ -1739,7 +1742,7 @@ function assertIsNotScalar($actual, string $message = '') * * @psalm-assert !callable $actual */ - function assertIsNotCallable($actual, string $message = '') + function assertIsNotCallable($actual, string $message = ''): void { Assert::assertIsNotCallable(...func_get_args()); } @@ -1756,7 +1759,7 @@ function assertIsNotCallable($actual, string $message = '') * * @psalm-assert !iterable $actual */ - function assertIsNotIterable($actual, string $message = '') + function assertIsNotIterable($actual, string $message = ''): void { Assert::assertIsNotIterable(...func_get_args()); } @@ -1771,7 +1774,7 @@ function assertIsNotIterable($actual, string $message = '') * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertMatchesRegularExpression(string $pattern, string $string, string $message = '') + function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void { Assert::assertMatchesRegularExpression(...func_get_args()); } @@ -1789,7 +1792,7 @@ function assertMatchesRegularExpression(string $pattern, string $string, string * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4086 * @see Assert::assertRegExp */ - function assertRegExp(string $pattern, string $string, string $message = '') + function assertRegExp(string $pattern, string $string, string $message = ''): void { Assert::assertRegExp(...func_get_args()); } @@ -1804,7 +1807,7 @@ function assertRegExp(string $pattern, string $string, string $message = '') * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = '') + function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = ''): void { Assert::assertDoesNotMatchRegularExpression(...func_get_args()); } @@ -1822,7 +1825,7 @@ function assertDoesNotMatchRegularExpression(string $pattern, string $string, st * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4089 * @see Assert::assertNotRegExp */ - function assertNotRegExp(string $pattern, string $string, string $message = '') + function assertNotRegExp(string $pattern, string $string, string $message = ''): void { Assert::assertNotRegExp(...func_get_args()); } @@ -1842,7 +1845,7 @@ function assertNotRegExp(string $pattern, string $string, string $message = '') * @throws InvalidArgumentException * @throws Exception */ - function assertSameSize($expected, $actual, string $message = '') + function assertSameSize($expected, $actual, string $message = ''): void { Assert::assertSameSize(...func_get_args()); } @@ -1862,7 +1865,7 @@ function assertSameSize($expected, $actual, string $message = '') * @throws InvalidArgumentException * @throws Exception */ - function assertNotSameSize($expected, $actual, string $message = '') + function assertNotSameSize($expected, $actual, string $message = ''): void { Assert::assertNotSameSize(...func_get_args()); } @@ -1877,7 +1880,7 @@ function assertNotSameSize($expected, $actual, string $message = '') * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringMatchesFormat(string $format, string $string, string $message = '') + function assertStringMatchesFormat(string $format, string $string, string $message = ''): void { Assert::assertStringMatchesFormat(...func_get_args()); } @@ -1892,7 +1895,7 @@ function assertStringMatchesFormat(string $format, string $string, string $messa * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringNotMatchesFormat(string $format, string $string, string $message = '') + function assertStringNotMatchesFormat(string $format, string $string, string $message = ''): void { Assert::assertStringNotMatchesFormat(...func_get_args()); } @@ -1907,7 +1910,7 @@ function assertStringNotMatchesFormat(string $format, string $string, string $me * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = '') + function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void { Assert::assertStringMatchesFormatFile(...func_get_args()); } @@ -1922,7 +1925,7 @@ function assertStringMatchesFormatFile(string $formatFile, string $string, strin * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = '') + function assertStringNotMatchesFormatFile(string $formatFile, string $string, string $message = ''): void { Assert::assertStringNotMatchesFormatFile(...func_get_args()); } @@ -1937,7 +1940,7 @@ function assertStringNotMatchesFormatFile(string $formatFile, string $string, st * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringStartsWith(string $prefix, string $string, string $message = '') + function assertStringStartsWith(string $prefix, string $string, string $message = ''): void { Assert::assertStringStartsWith(...func_get_args()); } @@ -1955,7 +1958,7 @@ function assertStringStartsWith(string $prefix, string $string, string $message * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringStartsNotWith($prefix, $string, string $message = '') + function assertStringStartsNotWith(string $prefix, string $string, string $message = ''): void { Assert::assertStringStartsNotWith(...func_get_args()); } @@ -1968,7 +1971,7 @@ function assertStringStartsNotWith($prefix, $string, string $message = '') * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringContainsString(string $needle, string $haystack, string $message = '') + function assertStringContainsString(string $needle, string $haystack, string $message = ''): void { Assert::assertStringContainsString(...func_get_args()); } @@ -1981,7 +1984,7 @@ function assertStringContainsString(string $needle, string $haystack, string $me * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = '') + function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void { Assert::assertStringContainsStringIgnoringCase(...func_get_args()); } @@ -1994,7 +1997,7 @@ function assertStringContainsStringIgnoringCase(string $needle, string $haystack * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringNotContainsString(string $needle, string $haystack, string $message = '') + function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void { Assert::assertStringNotContainsString(...func_get_args()); } @@ -2007,7 +2010,7 @@ function assertStringNotContainsString(string $needle, string $haystack, string * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = '') + function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void { Assert::assertStringNotContainsStringIgnoringCase(...func_get_args()); } @@ -2022,7 +2025,7 @@ function assertStringNotContainsStringIgnoringCase(string $needle, string $hayst * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringEndsWith(string $suffix, string $string, string $message = '') + function assertStringEndsWith(string $suffix, string $string, string $message = ''): void { Assert::assertStringEndsWith(...func_get_args()); } @@ -2037,7 +2040,7 @@ function assertStringEndsWith(string $suffix, string $string, string $message = * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertStringEndsNotWith(string $suffix, string $string, string $message = '') + function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void { Assert::assertStringEndsNotWith(...func_get_args()); } @@ -2053,7 +2056,7 @@ function assertStringEndsNotWith(string $suffix, string $string, string $message * @throws InvalidArgumentException * @throws Exception */ - function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = '') + function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void { Assert::assertXmlFileEqualsXmlFile(...func_get_args()); } @@ -2069,7 +2072,7 @@ function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, st * @throws InvalidArgumentException * @throws Exception */ - function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = '') + function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void { Assert::assertXmlFileNotEqualsXmlFile(...func_get_args()); } @@ -2087,7 +2090,7 @@ function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, * @throws InvalidArgumentException * @throws XmlException */ - function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = '') + function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void { Assert::assertXmlStringEqualsXmlFile(...func_get_args()); } @@ -2105,7 +2108,7 @@ function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $ * @throws InvalidArgumentException * @throws XmlException */ - function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = '') + function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, string $message = ''): void { Assert::assertXmlStringNotEqualsXmlFile(...func_get_args()); } @@ -2124,7 +2127,7 @@ function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, strin * @throws InvalidArgumentException * @throws XmlException */ - function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = '') + function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $message = ''): void { Assert::assertXmlStringEqualsXmlString(...func_get_args()); } @@ -2143,7 +2146,7 @@ function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $messag * @throws InvalidArgumentException * @throws XmlException */ - function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = '') + function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $message = ''): void { Assert::assertXmlStringNotEqualsXmlString(...func_get_args()); } @@ -2162,7 +2165,7 @@ function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $mes * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4091 * @see Assert::assertEqualXMLStructure */ - function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = '') + function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, bool $checkAttributes = false, string $message = ''): void { Assert::assertEqualXMLStructure(...func_get_args()); } @@ -2177,7 +2180,7 @@ function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actual * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertThat($value, Constraint $constraint, string $message = '') + function assertThat($value, Constraint $constraint, string $message = ''): void { Assert::assertThat(...func_get_args()); } @@ -2192,7 +2195,7 @@ function assertThat($value, Constraint $constraint, string $message = '') * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJson(string $actualJson, string $message = '') + function assertJson(string $actualJson, string $message = ''): void { Assert::assertJson(...func_get_args()); } @@ -2207,7 +2210,7 @@ function assertJson(string $actualJson, string $message = '') * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = '') + function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void { Assert::assertJsonStringEqualsJsonString(...func_get_args()); } @@ -2225,7 +2228,7 @@ function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJs * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string $message = '') + function assertJsonStringNotEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void { Assert::assertJsonStringNotEqualsJsonString(...func_get_args()); } @@ -2240,7 +2243,7 @@ function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = '') + function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void { Assert::assertJsonStringEqualsJsonFile(...func_get_args()); } @@ -2255,7 +2258,7 @@ function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = '') + function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void { Assert::assertJsonStringNotEqualsJsonFile(...func_get_args()); } @@ -2270,7 +2273,7 @@ function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJ * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = '') + function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void { Assert::assertJsonFileEqualsJsonFile(...func_get_args()); } @@ -2285,308 +2288,308 @@ function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, * @throws ExpectationFailedException * @throws InvalidArgumentException */ - function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = '') + function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void { Assert::assertJsonFileNotEqualsJsonFile(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\logicalAnd')) { - function logicalAnd() : LogicalAnd + function logicalAnd(): LogicalAnd { return Assert::logicalAnd(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\logicalOr')) { - function logicalOr() : LogicalOr + function logicalOr(): LogicalOr { return Assert::logicalOr(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\logicalNot')) { - function logicalNot(Constraint $constraint) : LogicalNot + function logicalNot(Constraint $constraint): LogicalNot { return Assert::logicalNot(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\logicalXor')) { - function logicalXor() : LogicalXor + function logicalXor(): LogicalXor { return Assert::logicalXor(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\anything')) { - function anything() : IsAnything + function anything(): IsAnything { return Assert::anything(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isTrue')) { - function isTrue() : IsTrue + function isTrue(): IsTrue { return Assert::isTrue(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\callback')) { - function callback(callable $callback) : Callback + function callback(callable $callback): Callback { return Assert::callback(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isFalse')) { - function isFalse() : IsFalse + function isFalse(): IsFalse { return Assert::isFalse(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isJson')) { - function isJson() : IsJson + function isJson(): IsJson { return Assert::isJson(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isNull')) { - function isNull() : IsNull + function isNull(): IsNull { return Assert::isNull(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isFinite')) { - function isFinite() : IsFinite + function isFinite(): IsFinite { return Assert::isFinite(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isInfinite')) { - function isInfinite() : IsInfinite + function isInfinite(): IsInfinite { return Assert::isInfinite(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isNan')) { - function isNan() : IsNan + function isNan(): IsNan { return Assert::isNan(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\containsEqual')) { - function containsEqual($value) : TraversableContainsEqual + function containsEqual($value): TraversableContainsEqual { return Assert::containsEqual(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\containsIdentical')) { - function containsIdentical($value) : TraversableContainsIdentical + function containsIdentical($value): TraversableContainsIdentical { return Assert::containsIdentical(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\containsOnly')) { - function containsOnly(string $type) : TraversableContainsOnly + function containsOnly(string $type): TraversableContainsOnly { return Assert::containsOnly(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\containsOnlyInstancesOf')) { - function containsOnlyInstancesOf(string $className) : TraversableContainsOnly + function containsOnlyInstancesOf(string $className): TraversableContainsOnly { return Assert::containsOnlyInstancesOf(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\arrayHasKey')) { - function arrayHasKey($key) : ArrayHasKey + function arrayHasKey($key): ArrayHasKey { return Assert::arrayHasKey(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\equalTo')) { - function equalTo($value) : IsEqual + function equalTo($value): IsEqual { return Assert::equalTo(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\equalToCanonicalizing')) { - function equalToCanonicalizing($value) : IsEqualCanonicalizing + function equalToCanonicalizing($value): IsEqualCanonicalizing { return Assert::equalToCanonicalizing(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\equalToIgnoringCase')) { - function equalToIgnoringCase($value) : IsEqualIgnoringCase + function equalToIgnoringCase($value): IsEqualIgnoringCase { return Assert::equalToIgnoringCase(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\equalToWithDelta')) { - function equalToWithDelta($value, float $delta) : IsEqualWithDelta + function equalToWithDelta($value, float $delta): IsEqualWithDelta { return Assert::equalToWithDelta(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isEmpty')) { - function isEmpty() : IsEmpty + function isEmpty(): IsEmpty { return Assert::isEmpty(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isWritable')) { - function isWritable() : IsWritable + function isWritable(): IsWritable { return Assert::isWritable(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isReadable')) { - function isReadable() : IsReadable + function isReadable(): IsReadable { return Assert::isReadable(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\directoryExists')) { - function directoryExists() : DirectoryExists + function directoryExists(): DirectoryExists { return Assert::directoryExists(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\fileExists')) { - function fileExists() : FileExists + function fileExists(): FileExists { return Assert::fileExists(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\greaterThan')) { - function greaterThan($value) : GreaterThan + function greaterThan($value): GreaterThan { return Assert::greaterThan(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\greaterThanOrEqual')) { - function greaterThanOrEqual($value) : LogicalOr + function greaterThanOrEqual($value): LogicalOr { return Assert::greaterThanOrEqual(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\classHasAttribute')) { - function classHasAttribute(string $attributeName) : ClassHasAttribute + function classHasAttribute(string $attributeName): ClassHasAttribute { return Assert::classHasAttribute(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\classHasStaticAttribute')) { - function classHasStaticAttribute(string $attributeName) : ClassHasStaticAttribute + function classHasStaticAttribute(string $attributeName): ClassHasStaticAttribute { return Assert::classHasStaticAttribute(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\objectHasAttribute')) { - function objectHasAttribute($attributeName) : ObjectHasAttribute + function objectHasAttribute($attributeName): ObjectHasAttribute { return Assert::objectHasAttribute(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\identicalTo')) { - function identicalTo($value) : IsIdentical + function identicalTo($value): IsIdentical { return Assert::identicalTo(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isInstanceOf')) { - function isInstanceOf(string $className) : IsInstanceOf + function isInstanceOf(string $className): IsInstanceOf { return Assert::isInstanceOf(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\isType')) { - function isType(string $type) : IsType + function isType(string $type): IsType { return Assert::isType(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\lessThan')) { - function lessThan($value) : LessThan + function lessThan($value): LessThan { return Assert::lessThan(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\lessThanOrEqual')) { - function lessThanOrEqual($value) : LogicalOr + function lessThanOrEqual($value): LogicalOr { return Assert::lessThanOrEqual(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\matchesRegularExpression')) { - function matchesRegularExpression(string $pattern) : RegularExpression + function matchesRegularExpression(string $pattern): RegularExpression { return Assert::matchesRegularExpression(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\matches')) { - function matches(string $string) : StringMatchesFormatDescription + function matches(string $string): StringMatchesFormatDescription { return Assert::matches(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\stringStartsWith')) { - function stringStartsWith($prefix) : StringStartsWith + function stringStartsWith($prefix): StringStartsWith { return Assert::stringStartsWith(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\stringContains')) { - function stringContains(string $string, bool $case = true) : StringContains + function stringContains(string $string, bool $case = true): StringContains { return Assert::stringContains(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\stringEndsWith')) { - function stringEndsWith(string $suffix) : StringEndsWith + function stringEndsWith(string $suffix): StringEndsWith { return Assert::stringEndsWith(...func_get_args()); } } if (! function_exists('PHPUnit\Framework\countOf')) { - function countOf(int $count) : Count + function countOf(int $count): Count { return Assert::countOf(...func_get_args()); } @@ -2597,7 +2600,7 @@ function countOf(int $count) : Count * Returns a matcher that matches when the method is executed * zero or more times. */ - function any() : AnyInvokedCountMatcher + function any(): AnyInvokedCountMatcher { return new AnyInvokedCountMatcher(); } @@ -2607,7 +2610,7 @@ function any() : AnyInvokedCountMatcher /** * Returns a matcher that matches when the method is never executed. */ - function never() : InvokedCountMatcher + function never(): InvokedCountMatcher { return new InvokedCountMatcher(0); } @@ -2618,7 +2621,7 @@ function never() : InvokedCountMatcher * Returns a matcher that matches when the method is executed * at least N times. */ - function atLeast(int $requiredInvocations) : InvokedAtLeastCountMatcher + function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher { return new InvokedAtLeastCountMatcher( $requiredInvocations @@ -2630,7 +2633,7 @@ function atLeast(int $requiredInvocations) : InvokedAtLeastCountMatcher /** * Returns a matcher that matches when the method is executed at least once. */ - function atLeastOnce() : InvokedAtLeastOnceMatcher + function atLeastOnce(): InvokedAtLeastOnceMatcher { return new InvokedAtLeastOnceMatcher(); } @@ -2640,7 +2643,7 @@ function atLeastOnce() : InvokedAtLeastOnceMatcher /** * Returns a matcher that matches when the method is executed exactly once. */ - function once() : InvokedCountMatcher + function once(): InvokedCountMatcher { return new InvokedCountMatcher(1); } @@ -2651,7 +2654,7 @@ function once() : InvokedCountMatcher * Returns a matcher that matches when the method is executed * exactly $count times. */ - function exactly(int $count) : InvokedCountMatcher + function exactly(int $count): InvokedCountMatcher { return new InvokedCountMatcher($count); } @@ -2662,7 +2665,7 @@ function exactly(int $count) : InvokedCountMatcher * Returns a matcher that matches when the method is executed * at most N times. */ - function atMost(int $allowedInvocations) : InvokedAtMostCountMatcher + function atMost(int $allowedInvocations): InvokedAtMostCountMatcher { return new InvokedAtMostCountMatcher($allowedInvocations); } @@ -2673,35 +2676,35 @@ function atMost(int $allowedInvocations) : InvokedAtMostCountMatcher * Returns a matcher that matches when the method is executed * at the given index. */ - function at(int $index) : InvokedAtIndexMatcher + function at(int $index): InvokedAtIndexMatcher { return new InvokedAtIndexMatcher($index); } } if (! function_exists('PHPUnit\Framework\returnValue')) { - function returnValue($value) : ReturnStub + function returnValue($value): ReturnStub { return new ReturnStub($value); } } if (! function_exists('PHPUnit\Framework\returnValueMap')) { - function returnValueMap(array $valueMap) : ReturnValueMapStub + function returnValueMap(array $valueMap): ReturnValueMapStub { return new ReturnValueMapStub($valueMap); } } if (! function_exists('PHPUnit\Framework\returnArgument')) { - function returnArgument(int $argumentIndex) : ReturnArgumentStub + function returnArgument(int $argumentIndex): ReturnArgumentStub { return new ReturnArgumentStub($argumentIndex); } } if (! function_exists('PHPUnit\Framework\returnCallback')) { - function returnCallback($callback) : ReturnCallbackStub + function returnCallback($callback): ReturnCallbackStub { return new ReturnCallbackStub($callback); } @@ -2713,21 +2716,21 @@ function returnCallback($callback) : ReturnCallbackStub * * This method is useful when mocking a fluent interface. */ - function returnSelf() : ReturnSelfStub + function returnSelf(): ReturnSelfStub { return new ReturnSelfStub(); } } if (! function_exists('PHPUnit\Framework\throwException')) { - function throwException(Throwable $exception) : ExceptionStub + function throwException(Throwable $exception): ExceptionStub { return new ExceptionStub($exception); } } if (! function_exists('PHPUnit\Framework\onConsecutiveCalls')) { - function onConsecutiveCalls() : ConsecutiveCallsStub + function onConsecutiveCalls(): ConsecutiveCallsStub { $args = func_get_args(); diff --git a/tests/PedantryTest.php b/tests/PedantryTest.php index e9b3f3fed..5e4cbf631 100644 --- a/tests/PedantryTest.php +++ b/tests/PedantryTest.php @@ -7,6 +7,7 @@ use ReflectionClass; use ReflectionMethod; use RegexIterator; + use function array_filter; use function array_map; use function realpath; @@ -15,6 +16,7 @@ use function strlen; use function substr; use function usort; + use const DIRECTORY_SEPARATOR; /** @@ -25,7 +27,7 @@ class PedantryTest extends TestCase /** * @dataProvider provideProjectClassNames */ - public function testMethodsAreOrderedAlphabeticallyByVisibility($className) + public function testMethodsAreOrderedAlphabeticallyByVisibility($className): void { $class = new ReflectionClass($className); $methods = $class->getMethods(); @@ -41,9 +43,11 @@ function (ReflectionMethod $method) use ($class) { if ($method->getModifiers() & ReflectionMethod::IS_PRIVATE) { return '2' . $method->getName(); } + if ($method->getModifiers() & ReflectionMethod::IS_PROTECTED) { return '1' . $method->getName(); } + if ($method->getModifiers() & ReflectionMethod::IS_PUBLIC) { return '0' . $method->getName(); } diff --git a/tests/SpecTests/AtlasDataLakeSpecTest.php b/tests/SpecTests/AtlasDataLakeSpecTest.php index d66f6be4a..901ac860e 100644 --- a/tests/SpecTests/AtlasDataLakeSpecTest.php +++ b/tests/SpecTests/AtlasDataLakeSpecTest.php @@ -6,6 +6,7 @@ use MongoDB\Driver\Cursor; use MongoDB\Tests\CommandObserver; use stdClass; + use function basename; use function current; use function explode; @@ -20,7 +21,7 @@ */ class AtlasDataLakeSpecTest extends FunctionalTestCase { - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -35,7 +36,7 @@ public function setUp() : void * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { foreach ($expected as $key => $value) { if ($value === null) { @@ -57,7 +58,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testAtlasDataLake(stdClass $test, array $runOn = null, array $data, $databaseName = null, $collectionName = null) + public function testAtlasDataLake(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset($runOn)) { $this->checkServerRequirements($runOn); @@ -109,8 +110,10 @@ public function provideTests() $group = basename($filename, '.json'); $runOn = $json->runOn ?? null; $data = $json->data ?? []; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $databaseName = $json->database_name ?? null; $collectionName = $json->collection_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; @@ -124,17 +127,17 @@ public function provideTests() /** * Prose test 1: Connect without authentication */ - public function testKillCursors() + public function testKillCursors(): void { $cursorId = null; $cursorNamespace = null; (new CommandObserver())->observe( - function () { + function (): void { $client = static::createTestClient(); $client->test->driverdata->find([], ['batchSize' => 2, 'limit' => 3]); }, - function (array $event) use (&$cursorId, &$cursorNamespace) { + function (array $event) use (&$cursorId, &$cursorNamespace): void { if ($event['started']->getCommandName() === 'find') { $this->assertArrayHasKey('succeeded', $event); @@ -162,7 +165,7 @@ function (array $event) use (&$cursorId, &$cursorNamespace) { $this->assertIsInt($cursorId); $this->assertIsString($cursorNamespace); - list($databaseName, $collectionName) = explode('.', $cursorNamespace, 2); + [$databaseName, $collectionName] = explode('.', $cursorNamespace, 2); $command = $event['started']->getCommand(); /* Assert that the killCursors command uses the namespace and @@ -190,7 +193,7 @@ function (array $event) use (&$cursorId, &$cursorNamespace) { /** * Prose test 2: Connect without authentication */ - public function testConnectWithoutAuth() + public function testConnectWithoutAuth(): void { /* Parse URI to remove userinfo component. The query string is left * as-is and must not include authMechanism or credentials. */ @@ -211,7 +214,7 @@ public function testConnectWithoutAuth() /** * Prose test 3: Connect with SCRAM-SHA-1 authentication */ - public function testConnectwithSCRAMSHA1() + public function testConnectwithSCRAMSHA1(): void { $client = static::createTestClient(null, ['authMechanism' => 'SCRAM-SHA-1']); $cursor = $client->selectDatabase($this->getDatabaseName())->command(['ping' => 1]); @@ -223,7 +226,7 @@ public function testConnectwithSCRAMSHA1() /** * Prose test 4: Connect with SCRAM-SHA-256 authentication */ - public function testConnectwithSCRAMSHA256() + public function testConnectwithSCRAMSHA256(): void { $client = static::createTestClient(null, ['authMechanism' => 'SCRAM-SHA-256']); $cursor = $client->selectDatabase($this->getDatabaseName())->command(['ping' => 1]); @@ -232,7 +235,7 @@ public function testConnectwithSCRAMSHA256() $this->assertCommandSucceeded(current($cursor->toArray())); } - private function isAtlasDataLake() : bool + private function isAtlasDataLake(): bool { $cursor = $this->manager->executeCommand( $this->getDatabaseName(), diff --git a/tests/SpecTests/ChangeStreamsSpecTest.php b/tests/SpecTests/ChangeStreamsSpecTest.php index 5dcb39132..c0ef72003 100644 --- a/tests/SpecTests/ChangeStreamsSpecTest.php +++ b/tests/SpecTests/ChangeStreamsSpecTest.php @@ -10,6 +10,7 @@ use MongoDB\Model\BSONDocument; use MultipleIterator; use stdClass; + use function basename; use function count; use function file_get_contents; @@ -33,7 +34,7 @@ class ChangeStreamsSpecTest extends FunctionalTestCase * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { if (isset($expected->getMore) && $expected->getMore === 42) { static::assertObjectHasAttribute('getMore', $actual); @@ -53,7 +54,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param array $expectedDocuments Expected documents * @param array $actualDocuments Actual documents */ - public static function assertResult(array $expectedDocuments, array $actualDocuments) + public static function assertResult(array $expectedDocuments, array $actualDocuments): void { static::assertCount(count($expectedDocuments), $actualDocuments); @@ -62,7 +63,7 @@ public static function assertResult(array $expectedDocuments, array $actualDocum $mi->attachIterator(new ArrayIterator($actualDocuments)); foreach ($mi as $documents) { - list($expectedDocument, $actualDocument) = $documents; + [$expectedDocument, $actualDocument] = $documents; $constraint = new DocumentsMatchConstraint($expectedDocument, true, true, ['42']); @@ -80,7 +81,7 @@ public static function assertResult(array $expectedDocuments, array $actualDocum * @param string $database2Name Name of alternate database under test * @param string $collection2Name Name of alternate collection under test */ - public function testChangeStreams(stdClass $test, $databaseName = null, $collectionName = null, $database2Name = null, $collection2Name = null) + public function testChangeStreams(stdClass $test, ?string $databaseName = null, ?string $collectionName = null, ?string $database2Name = null, ?string $collection2Name = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); @@ -168,10 +169,12 @@ public function provideTests() foreach (glob(__DIR__ . '/change-streams/*.json') as $filename) { $json = $this->decodeJson(file_get_contents($filename)); $group = basename($filename, '.json'); + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $databaseName = $json->database_name ?? null; $database2Name = $json->database2_name ?? null; $collectionName = $json->collection_name ?? null; $collection2Name = $json->collection2_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; @@ -189,7 +192,7 @@ public function provideTests() * @return ChangeStream * @throws LogicException if the target is unsupported */ - private function createChangeStream(stdClass $test) + private function createChangeStream(stdClass $test): ChangeStream { $context = $this->getContext(); $pipeline = $test->changeStreamPipeline ?? []; @@ -198,10 +201,13 @@ private function createChangeStream(stdClass $test) switch ($test->target) { case 'client': return $context->getClient()->watch($pipeline, $options); + case 'database': return $context->getDatabase()->watch($pipeline, $options); + case 'collection': return $context->getCollection()->watch($pipeline, $options); + default: throw new LogicException('Unsupported target: ' . $test->target); } @@ -214,7 +220,7 @@ private function createChangeStream(stdClass $test) * @param stdClass $test * @return array */ - private function createRunOn(stdClass $test) + private function createRunOn(stdClass $test): array { $req = new stdClass(); @@ -241,7 +247,7 @@ private function createRunOn(stdClass $test) * @param string $databaseName * @param string $collectionName */ - private function dropDatabasesAndCreateCollection($databaseName, $collectionName) + private function dropDatabasesAndCreateCollection(string $databaseName, string $collectionName): void { $context = $this->getContext(); @@ -257,7 +263,7 @@ private function dropDatabasesAndCreateCollection($databaseName, $collectionName * @param integer $limit * @return BSONDocument[] */ - private function iterateChangeStream(ChangeStream $changeStream, $limit = 0) + private function iterateChangeStream(ChangeStream $changeStream, int $limit = 0): array { if ($limit < 0) { throw new LogicException('$limit is negative'); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index f7d9aaf1f..8b9115467 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -20,6 +20,7 @@ use stdClass; use Throwable; use UnexpectedValueException; + use function base64_decode; use function basename; use function file_get_contents; @@ -39,9 +40,9 @@ */ class ClientSideEncryptionSpecTest extends FunctionalTestCase { - const LOCAL_MASTERKEY = 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk'; + public const LOCAL_MASTERKEY = 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk'; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -54,7 +55,7 @@ public function setUp() : void * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { static::assertDocumentsMatch($expected, $actual); } @@ -71,7 +72,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testClientSideEncryption(stdClass $test, array $runOn = null, array $data, array $keyVaultData = null, $jsonSchema = null, $databaseName = null, $collectionName = null) + public function testClientSideEncryption(stdClass $test, ?array $runOn = null, array $data, ?array $keyVaultData = null, $jsonSchema = null, ?string $databaseName = null, ?string $collectionName = null): void { if (isset($runOn)) { $this->checkServerRequirements($runOn); @@ -145,10 +146,12 @@ public function provideTests() $runOn = $json->runOn ?? null; $data = $json->data ?? []; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $keyVaultData = $json->key_vault_data ?? null; $jsonSchema = $json->json_schema ?? null; $databaseName = $json->database_name ?? null; $collectionName = $json->collection_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; @@ -164,7 +167,7 @@ public function provideTests() * * @dataProvider dataKeyProvider */ - public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey) + public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey): void { $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); $client = $this->getContext()->getClient(); @@ -211,7 +214,7 @@ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey) $keyAltName = $providerName . '_altname'; (new CommandObserver())->observe( - function () use ($clientEncryption, &$dataKeyId, $keyAltName, $providerName, $masterKey) { + function () use ($clientEncryption, &$dataKeyId, $keyAltName, $providerName, $masterKey): void { $keyData = ['keyAltNames' => [$keyAltName]]; if ($masterKey !== null) { $keyData['masterKey'] = $masterKey; @@ -219,7 +222,7 @@ function () use ($clientEncryption, &$dataKeyId, $keyAltName, $providerName, $ma $dataKeyId = $clientEncryption->createDataKey($providerName, $keyData); }, - function ($command) use (&$commands) { + function ($command) use (&$commands): void { $commands[] = $command; } ); @@ -295,7 +298,7 @@ public static function dataKeyProvider() * @testWith [false] * [true] */ - public function testExternalKeyVault($withExternalKeyVault) + public function testExternalKeyVault($withExternalKeyVault): void { $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); $client = $this->getContext()->getClient(); @@ -357,14 +360,14 @@ public function testExternalKeyVault($withExternalKeyVault) public static function provideBSONSizeLimitsAndBatchSplittingTests() { yield 'Test 1' => [ - static function (self $test, Collection $collection) { + static function (self $test, Collection $collection): void { $collection->insertOne(['_id' => 'over_2mib_under_16mib', 'unencrypted' => str_repeat('a', 2097152)]); $test->assertCollectionCount($collection->getNamespace(), 1); }, ]; yield 'Test 2' => [ - static function (self $test, Collection $collection, array $document) { + static function (self $test, Collection $collection, array $document): void { $collection->insertOne( ['_id' => 'encryption_exceeds_2mib', 'unencrypted' => str_repeat('a', 2097152 - 2000)] + $document ); @@ -373,16 +376,16 @@ static function (self $test, Collection $collection, array $document) { ]; yield 'Test 3' => [ - static function (self $test, Collection $collection) { + static function (self $test, Collection $collection): void { $commands = []; (new CommandObserver())->observe( - function () use ($collection) { + function () use ($collection): void { $collection->insertMany([ ['_id' => 'over_2mib_1', 'unencrypted' => str_repeat('a', 2097152)], ['_id' => 'over_2mib_2', 'unencrypted' => str_repeat('a', 2097152)], ]); }, - function ($command) use (&$commands) { + function ($command) use (&$commands): void { if ($command['started']->getCommandName() !== 'insert') { return; } @@ -396,10 +399,10 @@ function ($command) use (&$commands) { ]; yield 'Test 4' => [ - static function (self $test, Collection $collection, array $document) { + static function (self $test, Collection $collection, array $document): void { $commands = []; (new CommandObserver())->observe( - function () use ($collection, $document) { + function () use ($collection, $document): void { $collection->insertMany([ [ '_id' => 'encryption_exceeds_2mib_1', @@ -411,7 +414,7 @@ function () use ($collection, $document) { ] + $document, ]); }, - function ($command) use (&$commands) { + function ($command) use (&$commands): void { if ($command['started']->getCommandName() !== 'insert') { return; } @@ -425,14 +428,14 @@ function ($command) use (&$commands) { ]; yield 'Test 5' => [ - static function (self $test, Collection $collection) { + static function (self $test, Collection $collection): void { $collection->insertOne(['_id' => 'under_16mib', 'unencrypted' => str_repeat('a', 16777216 - 2000)]); $test->assertCollectionCount($collection->getNamespace(), 1); }, ]; yield 'Test 6' => [ - static function (self $test, Collection $collection, array $document) { + static function (self $test, Collection $collection, array $document): void { $test->expectException(BulkWriteException::class); $test->expectExceptionMessageMatches('#object to insert too large#'); $collection->insertOne(['_id' => 'encryption_exceeds_16mib', 'unencrypted' => str_repeat('a', 16777216 - 2000)] + $document); @@ -445,7 +448,7 @@ static function (self $test, Collection $collection, array $document) { * * @dataProvider provideBSONSizeLimitsAndBatchSplittingTests */ - public function testBSONSizeLimitsAndBatchSplitting(Closure $test) + public function testBSONSizeLimitsAndBatchSplitting(Closure $test): void { $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); $client = $this->getContext()->getClient(); @@ -477,7 +480,7 @@ public function testBSONSizeLimitsAndBatchSplitting(Closure $test) /** * Prose test: Views are prohibited */ - public function testViewsAreProhibited() + public function testViewsAreProhibited(): void { $client = static::createTestClient(); @@ -510,7 +513,7 @@ public function testViewsAreProhibited() * @testWith [true] * [false] */ - public function testCorpus($schemaMap = true) + public function testCorpus($schemaMap = true): void { $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); $client = $this->getContext()->getClient(); @@ -615,7 +618,7 @@ public function testCorpus($schemaMap = true) * * @dataProvider customEndpointProvider */ - public function testCustomEndpoint(Closure $test) + public function testCustomEndpoint(Closure $test): void { $client = static::createTestClient(); @@ -652,7 +655,7 @@ public static function customEndpointProvider() ]; yield 'Test 1' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey]); $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); $test->assertSame('test', $clientEncryption->decrypt($encrypted)); @@ -660,7 +663,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 2' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-1.amazonaws.com']]); $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); $test->assertSame('test', $clientEncryption->decrypt($encrypted)); @@ -668,7 +671,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 3' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $keyId = $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + [ 'endpoint' => 'kms.us-east-1.amazonaws.com:443']]); $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); $test->assertSame('test', $clientEncryption->decrypt($encrypted)); @@ -676,14 +679,14 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 4' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $test->expectException(ConnectionException::class); $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-1.amazonaws.com:12345']]); }, ]; yield 'Test 5' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $test->expectException(RuntimeException::class); $test->expectExceptionMessageMatches('#us-east-1#'); $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-2.amazonaws.com']]); @@ -691,7 +694,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 6' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $test->expectException(RuntimeException::class); $test->expectExceptionMessageMatches('#parse error#'); $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'example.com']]); @@ -699,7 +702,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 7' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($azureMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($azureMasterKey): void { $keyId = $clientEncryption->createDataKey('azure', ['masterKey' => $azureMasterKey]); $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); $test->assertSame('test', $clientEncryption->decrypt($encrypted)); @@ -711,7 +714,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 8' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey): void { $keyId = $clientEncryption->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); $test->assertSame('test', $clientEncryption->decrypt($encrypted)); @@ -723,7 +726,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio ]; yield 'Test 9' => [ - static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey) { + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey): void { $masterKey = $gcpMasterKey; $masterKey['endpoint'] = 'example.com:443'; @@ -737,7 +740,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio /** * Prose test: Bypass spawning mongocryptd (via mongocryptdBypassSpawn) */ - public function testBypassSpawningMongocryptdViaBypassSpawn() + public function testBypassSpawningMongocryptdViaBypassSpawn(): void { $autoEncryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', @@ -770,7 +773,7 @@ public function testBypassSpawningMongocryptdViaBypassSpawn() /** * Bypass spawning mongocryptd (via bypassAutoEncryption) */ - public function testBypassSpawningMongocryptdViaBypassAutoEncryption() + public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void { $autoEncryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', @@ -818,7 +821,7 @@ private function craftInt64($data) return unserialize($int64); } - private function createTestCollection($jsonSchema) + private function createTestCollection($jsonSchema): void { $options = empty($jsonSchema) ? [] : ['validator' => ['$jsonSchema' => $jsonSchema]]; $operation = new CreateCollection($this->getContext()->databaseName, $this->getContext()->collectionName, $options); @@ -887,7 +890,7 @@ private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEnc return $data->value; } - private function insertKeyVaultData(array $keyVaultData = null) + private function insertKeyVaultData(?array $keyVaultData = null): void { $context = $this->getContext(); $collection = $context->selectCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $context->defaultWriteOptions); diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index 6e203f931..ae4ac2eee 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -9,6 +9,7 @@ use MongoDB\Driver\Monitoring\CommandSubscriber; use MongoDB\Driver\Monitoring\CommandSucceededEvent; use MultipleIterator; + use function count; use function in_array; use function key; @@ -46,14 +47,17 @@ private function __construct(array $events) foreach ($events as $event) { switch (key($event)) { case 'command_failed_event': + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $this->expectedEvents[] = [$event->command_failed_event, CommandFailedEvent::class]; break; case 'command_started_event': + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $this->expectedEvents[] = [$event->command_started_event, CommandStartedEvent::class]; break; case 'command_succeeded_event': + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $this->expectedEvents[] = [$event->command_succeeded_event, CommandSucceededEvent::class]; break; @@ -150,7 +154,7 @@ public static function fromTransactions(array $expectedEvents) * * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ - public function commandFailed(CommandFailedEvent $event) + public function commandFailed(CommandFailedEvent $event): void { if ($this->ignoreCommandFailed || $this->isEventIgnored($event)) { return; @@ -164,7 +168,7 @@ public function commandFailed(CommandFailedEvent $event) * * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ - public function commandStarted(CommandStartedEvent $event) + public function commandStarted(CommandStartedEvent $event): void { if ($this->ignoreCommandStarted || $this->isEventIgnored($event)) { return; @@ -178,7 +182,7 @@ public function commandStarted(CommandStartedEvent $event) * * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ - public function commandSucceeded(CommandSucceededEvent $event) + public function commandSucceeded(CommandSucceededEvent $event): void { if ($this->ignoreCommandSucceeded || $this->isEventIgnored($event)) { return; @@ -190,7 +194,7 @@ public function commandSucceeded(CommandSucceededEvent $event) /** * Start command monitoring. */ - public function startMonitoring() + public function startMonitoring(): void { addSubscriber($this); } @@ -198,7 +202,7 @@ public function startMonitoring() /** * Stop command monitoring. */ - public function stopMonitoring() + public function stopMonitoring(): void { removeSubscriber($this); } @@ -209,7 +213,7 @@ public function stopMonitoring() * @param FunctionalTestCase $test Test instance * @param Context $context Execution context */ - public function assert(FunctionalTestCase $test, Context $context) + public function assert(FunctionalTestCase $test, Context $context): void { $test->assertCount(count($this->expectedEvents), $this->actualEvents); @@ -218,11 +222,12 @@ public function assert(FunctionalTestCase $test, Context $context) $mi->attachIterator(new ArrayIterator($this->actualEvents)); foreach ($mi as $events) { - list($expectedEventAndClass, $actualEvent) = $events; - list($expectedEvent, $expectedClass) = $expectedEventAndClass; + [$expectedEventAndClass, $actualEvent] = $events; + [$expectedEvent, $expectedClass] = $expectedEventAndClass; $test->assertInstanceOf($expectedClass, $actualEvent); + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps if (isset($expectedEvent->command_name)) { $test->assertSame($expectedEvent->command_name, $actualEvent->getCommandName()); } @@ -231,6 +236,8 @@ public function assert(FunctionalTestCase $test, Context $context) $test->assertSame($expectedEvent->database_name, $actualEvent->getDatabaseName()); } + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps + if (isset($expectedEvent->command)) { $test->assertInstanceOf(CommandStartedEvent::class, $actualEvent); $expectedCommand = $expectedEvent->command; diff --git a/tests/SpecTests/CommandMonitoringSpecTest.php b/tests/SpecTests/CommandMonitoringSpecTest.php index 0f9bf9075..bf1c73177 100644 --- a/tests/SpecTests/CommandMonitoringSpecTest.php +++ b/tests/SpecTests/CommandMonitoringSpecTest.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\SpecTests; use stdClass; + use function array_diff; use function basename; use function file_get_contents; @@ -25,7 +26,7 @@ class CommandMonitoringSpecTest extends FunctionalTestCase * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { if (isset($expected->getMore) && $expected->getMore === 42) { static::assertObjectHasAttribute('getMore', $actual); @@ -65,7 +66,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param stdClass $expected Expected command reply document * @param stdClass $actual Actual command reply document */ - public static function assertCommandReplyMatches(stdClass $expected, stdClass $actual) + public static function assertCommandReplyMatches(stdClass $expected, stdClass $actual): void { if (isset($expected->cursor->id) && $expected->cursor->id === 42) { static::assertObjectHasAttribute('cursor', $actual); @@ -141,7 +142,7 @@ public static function assertCommandReplyMatches(stdClass $expected, stdClass $a * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testCommandMonitoring(stdClass $test, array $data, $databaseName = null, $collectionName = null) + public function testCommandMonitoring(stdClass $test, array $data, ?string $databaseName = null, ?string $collectionName = null): void { $this->checkServerRequirements($this->createRunOn($test)); @@ -175,8 +176,10 @@ public function provideTests() $json = $this->decodeJson(file_get_contents($filename)); $group = basename($filename, '.json'); $data = $json->data ?? []; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $databaseName = $json->database_name ?? null; $collectionName = $json->collection_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; @@ -194,7 +197,7 @@ public function provideTests() * @param stdClass $test * @return array */ - private function createRunOn(stdClass $test) + private function createRunOn(stdClass $test): array { $req = new stdClass(); @@ -204,6 +207,7 @@ private function createRunOn(stdClass $test) self::TOPOLOGY_SHARDED, ]; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps /* Append ".99" as patch version, since command monitoring tests expect * the minor version to be an inclusive upper bound. */ if (isset($test->ignore_if_server_version_greater_than)) { @@ -218,6 +222,8 @@ private function createRunOn(stdClass $test) $req->topology = array_diff($topologies, $test->ignore_if_topology_type); } + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps + return [$req]; } } diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 4c9e16a8a..6769c9878 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -10,6 +10,7 @@ use MongoDB\Driver\WriteConcern; use PHPUnit\Framework\Assert; use stdClass; + use function array_diff_key; use function array_keys; use function getenv; @@ -31,7 +32,7 @@ final class Context /** @var Client|null */ private $client; - /** @var string */ + /** @var string|null */ public $collectionName; /** @var string */ @@ -43,7 +44,7 @@ final class Context /** @var array */ public $outcomeReadOptions = []; - /** @var string */ + /** @var string|null */ public $outcomeCollectionName; /** @var Session|null */ @@ -64,23 +65,19 @@ final class Context /** @var bool */ private $useEncryptedClient = false; - /** - * @param string $databaseName - * @param string $collectionName - */ - private function __construct($databaseName, $collectionName) + private function __construct(string $databaseName, ?string $collectionName) { $this->databaseName = $databaseName; $this->collectionName = $collectionName; $this->outcomeCollectionName = $collectionName; } - public function disableEncryption() + public function disableEncryption(): void { $this->useEncryptedClient = false; } - public function enableEncryption() + public function enableEncryption(): void { if (! $this->encryptedClient instanceof Client) { throw new LogicException('Cannot enable encryption without autoEncryption options'); @@ -251,7 +248,7 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti return $o; } - public static function getAWSCredentials() : array + public static function getAWSCredentials(): array { if (! getenv('AWS_ACCESS_KEY_ID') || ! getenv('AWS_SECRET_ACCESS_KEY')) { Assert::markTestSkipped('Please configure AWS credentials to use AWS KMS provider.'); @@ -263,7 +260,7 @@ public static function getAWSCredentials() : array ]; } - public static function getAzureCredentials() : array + public static function getAzureCredentials(): array { if (! getenv('AZURE_TENANT_ID') || ! getenv('AZURE_CLIENT_ID') || ! getenv('AZURE_CLIENT_SECRET')) { Assert::markTestSkipped('Please configure Azure credentials to use Azure KMS provider.'); @@ -276,7 +273,7 @@ public static function getAzureCredentials() : array ]; } - public static function getGCPCredentials() : array + public static function getGCPCredentials(): array { if (! getenv('GCP_EMAIL') || ! getenv('GCP_PRIVATE_KEY')) { Assert::markTestSkipped('Please configure GCP credentials to use GCP KMS provider.'); @@ -288,10 +285,7 @@ public static function getGCPCredentials() : array ]; } - /** - * @return Client - */ - public function getClient() + public function getClient(): Client { return $this->useEncryptedClient && $this->encryptedClient ? $this->encryptedClient : $this->client; } @@ -324,7 +318,7 @@ public function getGridFSBucket(array $bucketOptions = []) * @return array * @throws LogicException if any option keys are unsupported */ - public function prepareOptions(array $options) + public function prepareOptions(array $options): array { if (isset($options['readConcern']) && ! ($options['readConcern'] instanceof ReadConcern)) { $readConcern = (array) $options['readConcern']; @@ -380,7 +374,7 @@ public function prepareOptions(array $options) * @param array $args Operation arguments * @throws LogicException if the session placeholder is unsupported */ - public function replaceArgumentSessionPlaceholder(array &$args) + public function replaceArgumentSessionPlaceholder(array &$args): void { if (! isset($args['session'])) { return; @@ -408,7 +402,7 @@ public function replaceArgumentSessionPlaceholder(array &$args) * @param stdClass $command Command document * @throws LogicException if the session placeholder is unsupported */ - public function replaceCommandSessionPlaceholder(stdClass $command) + public function replaceCommandSessionPlaceholder(stdClass $command): void { if (! isset($command->lsid)) { return; diff --git a/tests/SpecTests/DocumentsMatchConstraint.php b/tests/SpecTests/DocumentsMatchConstraint.php index cfce06d89..786350433 100644 --- a/tests/SpecTests/DocumentsMatchConstraint.php +++ b/tests/SpecTests/DocumentsMatchConstraint.php @@ -31,6 +31,7 @@ use SebastianBergmann\Comparator\Factory; use stdClass; use Symfony\Bridge\PhpUnit\ConstraintTrait; + use function array_values; use function get_class; use function get_debug_type; @@ -40,6 +41,7 @@ use function is_scalar; use function method_exists; use function sprintf; + use const PHP_INT_SIZE; /** @@ -88,7 +90,7 @@ class DocumentsMatchConstraint extends Constraint * @param boolean $ignoreExtraKeysInEmbedded If true, ignore extra keys within embedded documents * @param array $placeholders Placeholders for any value */ - public function __construct($value, $ignoreExtraKeysInRoot = false, $ignoreExtraKeysInEmbedded = false, array $placeholders = []) + public function __construct($value, bool $ignoreExtraKeysInRoot = false, bool $ignoreExtraKeysInEmbedded = false, array $placeholders = []) { $this->value = $this->prepareBSON($value, true, $this->sortKeys); $this->ignoreExtraKeysInRoot = $ignoreExtraKeysInRoot; @@ -138,17 +140,19 @@ private function doEvaluate($other, $description = '', $returnResult = false) * @param string $expectedType * @param mixed $actualValue */ - private function assertBSONType($expectedType, $actualValue) + private function assertBSONType(string $expectedType, $actualValue): void { switch ($expectedType) { case 'double': (new IsType('float'))->evaluate($actualValue); return; + case 'string': (new IsType('string'))->evaluate($actualValue); return; + case 'object': $constraints = [ new IsType('object'), @@ -167,6 +171,7 @@ private function assertBSONType($expectedType, $actualValue) $constraint->evaluate($actualValue); return; + case 'array': $constraints = [ new IsType('array'), @@ -185,54 +190,67 @@ private function assertBSONType($expectedType, $actualValue) $constraint->evaluate($actualValue); return; + case 'binData': (new IsInstanceOf(BinaryInterface::class))->evaluate($actualValue); return; + case 'undefined': (new IsInstanceOf(Undefined::class))->evaluate($actualValue); return; + case 'objectId': (new IsInstanceOf(ObjectId::class))->evaluate($actualValue); return; + case 'boolean': (new IsType('bool'))->evaluate($actualValue); return; + case 'date': (new IsInstanceOf(UTCDateTime::class))->evaluate($actualValue); return; + case 'null': (new IsNull())->evaluate($actualValue); return; + case 'regex': (new IsInstanceOf(Regex::class))->evaluate($actualValue); return; + case 'dbPointer': (new IsInstanceOf(DBPointer::class))->evaluate($actualValue); return; + case 'javascript': (new IsInstanceOf(Javascript::class))->evaluate($actualValue); return; + case 'symbol': (new IsInstanceOf(Symbol::class))->evaluate($actualValue); return; + case 'int': (new IsType('int'))->evaluate($actualValue); return; + case 'timestamp': (new IsInstanceOf(Timestamp::class))->evaluate($actualValue); return; + case 'long': if (PHP_INT_SIZE == 4) { (new IsInstanceOf(Int64::class))->evaluate($actualValue); @@ -241,14 +259,17 @@ private function assertBSONType($expectedType, $actualValue) } return; + case 'decimal': (new IsInstanceOf(Decimal128::class))->evaluate($actualValue); return; + case 'minKey': (new IsInstanceOf(MinKey::class))->evaluate($actualValue); return; + case 'maxKey': (new IsInstanceOf(MaxKey::class))->evaluate($actualValue); @@ -265,7 +286,7 @@ private function assertBSONType($expectedType, $actualValue) * @param string $keyPrefix * @throws RuntimeException if the documents do not match */ - private function assertEquals(ArrayObject $expected, ArrayObject $actual, $ignoreExtraKeys, $keyPrefix = '') + private function assertEquals(ArrayObject $expected, ArrayObject $actual, bool $ignoreExtraKeys, string $keyPrefix = ''): void { if (get_class($expected) !== get_class($actual)) { throw new RuntimeException(sprintf( @@ -293,8 +314,10 @@ private function assertEquals(ArrayObject $expected, ArrayObject $actual, $ignor continue; } - if (($expectedValue instanceof BSONArray && $actualValue instanceof BSONArray) || - ($expectedValue instanceof BSONDocument && $actualValue instanceof BSONDocument)) { + if ( + ($expectedValue instanceof BSONArray && $actualValue instanceof BSONArray) || + ($expectedValue instanceof BSONDocument && $actualValue instanceof BSONDocument) + ) { $this->assertEquals($expectedValue, $actualValue, $this->ignoreExtraKeysInEmbedded, $keyPrefix . $key . '.'); continue; } @@ -411,7 +434,7 @@ private function doToString() * @return BSONDocument|BSONArray * @throws InvalidArgumentException if $bson is not an array or object */ - private function prepareBSON($bson, $isRoot, $sortKeys = false) + private function prepareBSON($bson, bool $isRoot, bool $sortKeys = false) { if (! is_array($bson) && ! is_object($bson)) { throw new InvalidArgumentException('$bson is not an array or object'); diff --git a/tests/SpecTests/DocumentsMatchConstraintTest.php b/tests/SpecTests/DocumentsMatchConstraintTest.php index 1d4abddfe..eca64d344 100644 --- a/tests/SpecTests/DocumentsMatchConstraintTest.php +++ b/tests/SpecTests/DocumentsMatchConstraintTest.php @@ -15,14 +15,16 @@ use MongoDB\Model\BSONDocument; use MongoDB\Tests\TestCase; use PHPUnit\Framework\ExpectationFailedException; + use function MongoDB\BSON\fromJSON; use function MongoDB\BSON\toPHP; use function unserialize; + use const PHP_INT_SIZE; class DocumentsMatchConstraintTest extends TestCase { - public function testIgnoreExtraKeysInRoot() + public function testIgnoreExtraKeysInRoot(): void { $c = new DocumentsMatchConstraint(['x' => 1, 'y' => ['a' => 1, 'b' => 2]], true, false); @@ -41,7 +43,7 @@ public function testIgnoreExtraKeysInRoot() $this->assertResult(false, $c, [1, ['a' => 1, 'b' => 2]], 'Extra keys in embedded are not permitted'); } - public function testIgnoreExtraKeysInEmbedded() + public function testIgnoreExtraKeysInEmbedded(): void { $c = new DocumentsMatchConstraint(['x' => 1, 'y' => ['a' => 1, 'b' => 2]], false, true); @@ -62,7 +64,7 @@ public function testIgnoreExtraKeysInEmbedded() $this->assertResult(false, $c, [1, ['a' => 2]], 'Keys must have the correct value'); } - public function testPlaceholders() + public function testPlaceholders(): void { $c = new DocumentsMatchConstraint(['x' => '42', 'y' => 42, 'z' => ['a' => 24]], false, false, [24, 42]); @@ -74,7 +76,7 @@ public function testPlaceholders() /** * @dataProvider provideBSONTypes */ - public function testBSONTypeAssertions($type, $value) + public function testBSONTypeAssertions($type, $value): void { $constraint = new DocumentsMatchConstraint(['x' => ['$$type' => $type]]); @@ -114,7 +116,7 @@ public function provideBSONTypes() /** * @dataProvider errorMessageProvider */ - public function testErrorMessages($expectedMessagePart, DocumentsMatchConstraint $constraint, $actualValue) + public function testErrorMessages($expectedMessagePart, DocumentsMatchConstraint $constraint, $actualValue): void { try { $constraint->evaluate($actualValue); @@ -161,7 +163,7 @@ public function errorMessageProvider() ]; } - private function assertResult($expectedResult, DocumentsMatchConstraint $constraint, $value, $message) + private function assertResult($expectedResult, DocumentsMatchConstraint $constraint, $value, $message): void { $this->assertSame($expectedResult, $constraint->evaluate($value, '', true), $message); } diff --git a/tests/SpecTests/ErrorExpectation.php b/tests/SpecTests/ErrorExpectation.php index 6e0c03806..9f40d003a 100644 --- a/tests/SpecTests/ErrorExpectation.php +++ b/tests/SpecTests/ErrorExpectation.php @@ -11,6 +11,7 @@ use MongoDB\Tests\TestCase; use stdClass; use Throwable; + use function get_class; use function is_array; use function is_string; @@ -69,6 +70,7 @@ public static function fromChangeStreams(stdClass $result) if (! self::isArrayOfStrings($result->error->errorLabels)) { throw InvalidArgumentException::invalidType('errorLabels', $result->error->errorLabels, 'string[]'); } + $o->includedLabels = $result->error->errorLabels; $o->isExpected = true; } @@ -122,6 +124,7 @@ public static function fromRetryableWrites(stdClass $outcome) if (! self::isArrayOfStrings($outcome->result->errorLabelsContain)) { throw InvalidArgumentException::invalidType('errorLabelsContain', $outcome->result->errorLabelsContain, 'string[]'); } + $o->includedLabels = $outcome->result->errorLabelsContain; } @@ -129,6 +132,7 @@ public static function fromRetryableWrites(stdClass $outcome) if (! self::isArrayOfStrings($outcome->result->errorLabelsOmit)) { throw InvalidArgumentException::invalidType('errorLabelsOmit', $outcome->result->errorLabelsOmit, 'string[]'); } + $o->excludedLabels = $outcome->result->errorLabelsOmit; } @@ -154,7 +158,7 @@ public static function noError() * @param TestCase $test Test instance for performing assertions * @param Exception|null $actual Exception (if any) from the actual outcome */ - public function assert(TestCase $test, Throwable $actual = null) + public function assert(TestCase $test, ?Throwable $actual = null): void { if (! $this->isExpected) { if ($actual !== null) { @@ -198,7 +202,7 @@ public function isExpected() * @param TestCase $test Test instance for performing assertions * @param Exception|null $actual Exception (if any) from the actual outcome */ - private function assertCodeName(TestCase $test, Throwable $actual = null) + private function assertCodeName(TestCase $test, ?Throwable $actual = null): void { /* BulkWriteException does not expose codeName for server errors. Work * around this be comparing the error code against a map. @@ -252,6 +256,7 @@ private static function fromGenericOperation(stdClass $operation) if (! self::isArrayOfStrings($result->errorLabelsContain)) { throw InvalidArgumentException::invalidType('errorLabelsContain', $result->errorLabelsContain, 'string[]'); } + $o->includedLabels = $result->errorLabelsContain; $o->isExpected = true; } @@ -260,6 +265,7 @@ private static function fromGenericOperation(stdClass $operation) if (! self::isArrayOfStrings($result->errorLabelsOmit)) { throw InvalidArgumentException::invalidType('errorLabelsOmit', $result->errorLabelsOmit, 'string[]'); } + $o->excludedLabels = $result->errorLabelsOmit; $o->isExpected = true; } diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index 04bf6ac66..9c6939639 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -11,6 +11,7 @@ use PHPUnit\Framework\SkippedTest; use stdClass; use UnexpectedValueException; + use function in_array; use function json_encode; use function MongoDB\BSON\fromJSON; @@ -25,21 +26,21 @@ */ class FunctionalTestCase extends BaseFunctionalTestCase { - const TOPOLOGY_SINGLE = 'single'; - const TOPOLOGY_REPLICASET = 'replicaset'; - const TOPOLOGY_SHARDED = 'sharded'; + public const TOPOLOGY_SINGLE = 'single'; + public const TOPOLOGY_REPLICASET = 'replicaset'; + public const TOPOLOGY_SHARDED = 'sharded'; /** @var Context|null */ private $context; - public function setUp() : void + public function setUp(): void { parent::setUp(); $this->context = null; } - public function tearDown() : void + public function tearDown(): void { $this->context = null; @@ -55,7 +56,7 @@ public function tearDown() : void * @param stdClass $expectedCommand Expected command document * @param stdClass $actualCommand Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { throw new LogicException(sprintf('%s does not assert CommandStartedEvents', static::class)); } @@ -69,7 +70,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param stdClass $expected Expected command reply document * @param stdClass $actual Actual command reply document */ - public static function assertCommandReplyMatches(stdClass $expected, stdClass $actual) + public static function assertCommandReplyMatches(stdClass $expected, stdClass $actual): void { throw new LogicException(sprintf('%s does not assert CommandSucceededEvents', static::class)); } @@ -83,7 +84,7 @@ public static function assertCommandReplyMatches(stdClass $expected, stdClass $a * @param array|object $actualDocument * @param string $message */ - protected static function assertDocumentsMatch($expectedDocument, $actualDocument, $message = '') + protected static function assertDocumentsMatch($expectedDocument, $actualDocument, string $message = ''): void { $constraint = new DocumentsMatchConstraint($expectedDocument, true, true); @@ -96,7 +97,7 @@ protected static function assertDocumentsMatch($expectedDocument, $actualDocumen * @param array $expectedDocuments * @param int $resultExpectation */ - protected function assertOutcomeCollectionData(array $expectedDocuments, $resultExpectation = ResultExpectation::ASSERT_SAME_DOCUMENT) + protected function assertOutcomeCollectionData(array $expectedDocuments, int $resultExpectation = ResultExpectation::ASSERT_SAME_DOCUMENT): void { $outcomeCollection = $this->getOutcomeCollection($this->getContext()->outcomeReadOptions); @@ -105,7 +106,7 @@ protected function assertOutcomeCollectionData(array $expectedDocuments, $result $mi->attachIterator($outcomeCollection->find([], ['sort' => ['_id' => 1]])); foreach ($mi as $documents) { - list($expectedDocument, $actualDocument) = $documents; + [$expectedDocument, $actualDocument] = $documents; $this->assertNotNull($expectedDocument); $this->assertNotNull($actualDocument); @@ -130,7 +131,7 @@ protected function assertOutcomeCollectionData(array $expectedDocuments, $result * @param array $runOn * @throws SkippedTest if the server requirements are not met */ - protected function checkServerRequirements(array $runOn) + protected function checkServerRequirements(array $runOn): void { foreach ($runOn as $req) { $minServerVersion = $req->minServerVersion ?? null; @@ -155,9 +156,9 @@ protected function checkServerRequirements(array $runOn) * proper handling of special types. * * @param string $json - * @return array + * @return array|object */ - protected function decodeJson($json) + protected function decodeJson(string $json) { return toPHP(fromJSON($json)); } @@ -168,7 +169,7 @@ protected function decodeJson($json) * @return Context * @throws LogicException if the context has not been set */ - protected function getContext() + protected function getContext(): Context { if (! $this->context instanceof Context) { throw new LogicException('Context has not been set'); @@ -182,7 +183,7 @@ protected function getContext() * * @param Context $context */ - protected function setContext(Context $context) + protected function setContext(Context $context): void { $this->context = $context; } @@ -190,7 +191,7 @@ protected function setContext(Context $context) /** * Drop the test and outcome collections by dropping them. */ - protected function dropTestAndOutcomeCollections() + protected function dropTestAndOutcomeCollections(): void { $context = $this->getContext(); @@ -225,7 +226,7 @@ protected function dropTestAndOutcomeCollections() * @param array $documents * @param string|null $collectionName */ - protected function insertDataFixtures(array $documents, $collectionName = null) + protected function insertDataFixtures(array $documents, ?string $collectionName = null): void { if (empty($documents)) { return; @@ -253,7 +254,7 @@ private function getOutcomeCollection(array $collectionOptions = []) * @return string * @throws UnexpectedValueException if topology is neither single nor RS nor sharded */ - private function getTopology() + private function getTopology(): string { $topologyTypeMap = [ Server::TYPE_STANDALONE => self::TOPOLOGY_SINGLE, @@ -278,7 +279,7 @@ private function getTopology() * @param array|null $topologies * @return boolean */ - private function isServerRequirementSatisifed($minServerVersion, $maxServerVersion, array $topologies = null) + private function isServerRequirementSatisifed(?string $minServerVersion, ?string $maxServerVersion, ?array $topologies = null): bool { $serverVersion = $this->getServerVersion(); diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index bd34e735f..626cd313f 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -17,6 +17,7 @@ use MongoDB\Operation\FindOneAndReplace; use MongoDB\Operation\FindOneAndUpdate; use stdClass; + use function array_diff_key; use function array_map; use function fclose; @@ -32,15 +33,15 @@ */ final class Operation { - const OBJECT_CLIENT = 'client'; - const OBJECT_COLLECTION = 'collection'; - const OBJECT_DATABASE = 'database'; - const OBJECT_GRIDFS_BUCKET = 'gridfsbucket'; - const OBJECT_SELECT_COLLECTION = 'selectCollection'; - const OBJECT_SELECT_DATABASE = 'selectDatabase'; - const OBJECT_SESSION0 = 'session0'; - const OBJECT_SESSION1 = 'session1'; - const OBJECT_TEST_RUNNER = 'testRunner'; + public const OBJECT_CLIENT = 'client'; + public const OBJECT_COLLECTION = 'collection'; + public const OBJECT_DATABASE = 'database'; + public const OBJECT_GRIDFS_BUCKET = 'gridfsbucket'; + public const OBJECT_SELECT_COLLECTION = 'selectCollection'; + public const OBJECT_SELECT_DATABASE = 'selectDatabase'; + public const OBJECT_SESSION0 = 'session0'; + public const OBJECT_SESSION1 = 'session1'; + public const OBJECT_TEST_RUNNER = 'testRunner'; /** @var ErrorExpectation|null */ public $errorExpectation; @@ -155,7 +156,7 @@ public static function fromCommandMonitoring(stdClass $operation) * * @return Operation */ - private static function fromConvenientTransactions(stdClass $operation) + private static function fromConvenientTransactions(stdClass $operation): Operation { $o = new self($operation); @@ -245,7 +246,7 @@ public static function fromTransactions(stdClass $operation) * @param Context $context Execution context * @param bool $bubbleExceptions If true, any exception that was caught is rethrown */ - public function assert(FunctionalTestCase $test, Context $context, $bubbleExceptions = false) + public function assert(FunctionalTestCase $test, Context $context, bool $bubbleExceptions = false): void { $result = null; $exception = null; @@ -296,32 +297,41 @@ private function execute(FunctionalTestCase $test, Context $context) $client = $context->getClient(); return $this->executeForClient($client, $context); + case self::OBJECT_COLLECTION: $collection = $context->getCollection($this->collectionOptions, $this->databaseOptions); return $this->executeForCollection($collection, $context); + case self::OBJECT_DATABASE: $database = $context->getDatabase(); return $this->executeForDatabase($database, $context); + case self::OBJECT_GRIDFS_BUCKET: $bucket = $context->getGridFSBucket(); return $this->executeForGridFSBucket($bucket, $context); + case self::OBJECT_SELECT_COLLECTION: $collection = $context->selectCollection($this->databaseName, $this->collectionName, $this->collectionOptions, $this->databaseOptions); return $this->executeForCollection($collection, $context); + case self::OBJECT_SELECT_DATABASE: $database = $context->selectDatabase($this->databaseName); return $this->executeForDatabase($database, $context); + case self::OBJECT_SESSION0: return $this->executeForSession($context->session0, $test, $context); + case self::OBJECT_SESSION1: return $this->executeForSession($context->session1, $test, $context); + case self::OBJECT_TEST_RUNNER: return $this->executeForTestRunner($test, $context); + default: throw new LogicException('Unsupported object: ' . $this->object); } @@ -343,13 +353,16 @@ private function executeForClient(Client $client, Context $context) switch ($this->name) { case 'listDatabaseNames': return iterator_to_array($client->listDatabaseNames($args)); + case 'listDatabases': return $client->listDatabases($args); + case 'watch': return $client->watch( $args['pipeline'] ?? [], array_diff_key($args, ['pipeline' => 1]) ); + default: throw new LogicException('Unsupported client operation: ' . $this->name); } @@ -374,6 +387,7 @@ private function executeForCollection(Collection $collection, Context $context) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); + case 'bulkWrite': // Merge nested and top-level options (see: SPEC-1158) $options = isset($args['options']) ? (array) $args['options'] : []; @@ -384,16 +398,19 @@ private function executeForCollection(Collection $collection, Context $context) array_map([$this, 'prepareBulkWriteRequest'], $args['requests']), $options ); + case 'createIndex': return $collection->createIndex( $args['keys'], array_diff_key($args, ['keys' => 1]) ); + case 'dropIndex': return $collection->dropIndex( $args['name'], array_diff_key($args, ['name' => 1]) ); + case 'count': case 'countDocuments': case 'find': @@ -401,8 +418,10 @@ private function executeForCollection(Collection $collection, Context $context) $args['filter'] ?? [], array_diff_key($args, ['filter' => 1]) ); + case 'estimatedDocumentCount': return $collection->estimatedDocumentCount($args); + case 'deleteMany': case 'deleteOne': case 'findOneAndDelete': @@ -410,16 +429,20 @@ private function executeForCollection(Collection $collection, Context $context) $args['filter'], array_diff_key($args, ['filter' => 1]) ); + case 'distinct': return $collection->distinct( $args['fieldName'], $args['filter'] ?? [], array_diff_key($args, ['fieldName' => 1, 'filter' => 1]) ); + case 'drop': return $collection->drop($args); + case 'findOne': return $collection->findOne($args['filter'], array_diff_key($args, ['filter' => 1])); + case 'findOneAndReplace': if (isset($args['returnDocument'])) { $args['returnDocument'] = 'after' === strtolower($args['returnDocument']) @@ -427,13 +450,13 @@ private function executeForCollection(Collection $collection, Context $context) : FindOneAndReplace::RETURN_DOCUMENT_BEFORE; } // Fall through - case 'replaceOne': return $collection->{$this->name}( $args['filter'], $args['replacement'], array_diff_key($args, ['filter' => 1, 'replacement' => 1]) ); + case 'findOneAndUpdate': if (isset($args['returnDocument'])) { $args['returnDocument'] = 'after' === strtolower($args['returnDocument']) @@ -441,7 +464,6 @@ private function executeForCollection(Collection $collection, Context $context) : FindOneAndUpdate::RETURN_DOCUMENT_BEFORE; } // Fall through - case 'updateMany': case 'updateOne': return $collection->{$this->name}( @@ -449,6 +471,7 @@ private function executeForCollection(Collection $collection, Context $context) $args['update'], array_diff_key($args, ['filter' => 1, 'update' => 1]) ); + case 'insertMany': // Merge nested and top-level options (see: SPEC-1158) $options = isset($args['options']) ? (array) $args['options'] : []; @@ -458,13 +481,16 @@ private function executeForCollection(Collection $collection, Context $context) $args['documents'], $options ); + case 'insertOne': return $collection->insertOne( $args['document'], array_diff_key($args, ['document' => 1]) ); + case 'listIndexes': return $collection->listIndexes($args); + case 'mapReduce': return $collection->mapReduce( $args['map'], @@ -472,11 +498,13 @@ private function executeForCollection(Collection $collection, Context $context) $args['out'], array_diff_key($args, ['map' => 1, 'reduce' => 1, 'out' => 1]) ); + case 'watch': return $collection->watch( $args['pipeline'] ?? [], array_diff_key($args, ['pipeline' => 1]) ); + default: throw new LogicException('Unsupported collection operation: ' . $this->name); } @@ -501,30 +529,37 @@ private function executeForDatabase(Database $database, Context $context) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); + case 'createCollection': return $database->createCollection( $args['collection'], array_diff_key($args, ['collection' => 1]) ); + case 'dropCollection': return $database->dropCollection( $args['collection'], array_diff_key($args, ['collection' => 1]) ); + case 'listCollectionNames': return iterator_to_array($database->listCollectionNames($args)); + case 'listCollections': return $database->listCollections($args); + case 'runCommand': return $database->command( $args['command'], array_diff_key($args, ['command' => 1]) )->toArray()[0]; + case 'watch': return $database->watch( $args['pipeline'] ?? [], array_diff_key($args, ['pipeline' => 1]) ); + default: throw new LogicException('Unsupported database operation: ' . $this->name); } @@ -553,6 +588,7 @@ private function executeForGridFSBucket(Bucket $bucket, Context $context) } finally { fclose($stream); } + break; case 'download_by_name': @@ -564,6 +600,7 @@ private function executeForGridFSBucket(Bucket $bucket, Context $context) } finally { fclose($stream); } + break; default: @@ -585,19 +622,22 @@ private function executeForSession(Session $session, FunctionalTestCase $test, C switch ($this->name) { case 'abortTransaction': return $session->abortTransaction(); + case 'commitTransaction': return $session->commitTransaction(); + case 'startTransaction': $options = isset($this->arguments['options']) ? (array) $this->arguments['options'] : []; return $session->startTransaction($context->prepareOptions($options)); + case 'withTransaction': /** @var self[] $callbackOperations */ $callbackOperations = array_map(function ($operation) { return self::fromConvenientTransactions($operation); }, $this->arguments['callback']->operations); - $callback = function () use ($callbackOperations, $test, $context) { + $callback = function () use ($callbackOperations, $test, $context): void { foreach ($callbackOperations as $operation) { $operation->assert($test, $context, true); } @@ -606,6 +646,7 @@ private function executeForSession(Session $session, FunctionalTestCase $test, C $options = isset($this->arguments['options']) ? (array) $this->arguments['options'] : []; return with_transaction($session, $callback, $context->prepareOptions($options)); + default: throw new LogicException('Unsupported session operation: ' . $this->name); } @@ -624,6 +665,7 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context $test->assertContains($collectionName, $context->selectDatabase($databaseName)->listCollectionNames()); return null; + case 'assertCollectionNotExists': $databaseName = $args['database']; $collectionName = $args['collection']; @@ -631,6 +673,7 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context $test->assertNotContains($collectionName, $context->selectDatabase($databaseName)->listCollectionNames()); return null; + case 'assertIndexExists': $databaseName = $args['database']; $collectionName = $args['collection']; @@ -639,6 +682,7 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context $test->assertContains($indexName, $this->getIndexNames($context, $databaseName, $collectionName)); return null; + case 'assertIndexNotExists': $databaseName = $args['database']; $collectionName = $args['collection']; @@ -647,26 +691,31 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context $test->assertNotContains($indexName, $this->getIndexNames($context, $databaseName, $collectionName)); return null; + case 'assertSessionPinned': $test->assertInstanceOf(Session::class, $args['session']); $test->assertInstanceOf(Server::class, $args['session']->getServer()); return null; + case 'assertSessionTransactionState': $test->assertInstanceOf(Session::class, $args['session']); $test->assertSame($this->arguments['state'], $args['session']->getTransactionState()); return null; + case 'assertSessionUnpinned': $test->assertInstanceOf(Session::class, $args['session']); $test->assertNull($args['session']->getServer()); return null; + case 'targetedFailPoint': $test->assertInstanceOf(Session::class, $args['session']); $test->configureFailPoint($this->arguments['failPoint'], $args['session']->getServer()); return null; + default: throw new LogicException('Unsupported test runner operation: ' . $this->name); } @@ -678,7 +727,7 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context * * @return array */ - private function getIndexNames(Context $context, $databaseName, $collectionName) + private function getIndexNames(Context $context, string $databaseName, string $collectionName): array { return array_map( function (IndexInfo $indexInfo) { @@ -696,16 +745,21 @@ private function getResultAssertionType() switch ($this->object) { case self::OBJECT_CLIENT: return $this->getResultAssertionTypeForClient(); + case self::OBJECT_COLLECTION: return $this->getResultAssertionTypeForCollection(); + case self::OBJECT_DATABASE: return $this->getResultAssertionTypeForDatabase(); + case self::OBJECT_GRIDFS_BUCKET: return ResultExpectation::ASSERT_SAME; + case self::OBJECT_SESSION0: case self::OBJECT_SESSION1: case self::OBJECT_TEST_RUNNER: return ResultExpectation::ASSERT_NOTHING; + default: throw new LogicException('Unsupported object: ' . $this->object); } @@ -719,10 +773,13 @@ private function getResultAssertionTypeForClient() switch ($this->name) { case 'listDatabaseNames': return ResultExpectation::ASSERT_SAME; + case 'listDatabases': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + case 'watch': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + default: throw new LogicException('Unsupported client operation: ' . $this->name); } @@ -744,43 +801,58 @@ private function getResultAssertionTypeForCollection() } return ResultExpectation::ASSERT_SAME_DOCUMENTS; + case 'bulkWrite': return ResultExpectation::ASSERT_BULKWRITE; + case 'count': case 'countDocuments': return ResultExpectation::ASSERT_SAME; + case 'createIndex': case 'dropIndex': return ResultExpectation::ASSERT_MATCHES_DOCUMENT; + case 'distinct': case 'estimatedDocumentCount': return ResultExpectation::ASSERT_SAME; + case 'deleteMany': case 'deleteOne': return ResultExpectation::ASSERT_DELETE; + case 'drop': return ResultExpectation::ASSERT_NOTHING; + case 'findOne': case 'findOneAndDelete': case 'findOneAndReplace': case 'findOneAndUpdate': return ResultExpectation::ASSERT_SAME_DOCUMENT; + case 'find': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + case 'insertMany': return ResultExpectation::ASSERT_INSERTMANY; + case 'insertOne': return ResultExpectation::ASSERT_INSERTONE; + case 'listIndexes': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + case 'mapReduce': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + case 'replaceOne': case 'updateMany': case 'updateOne': return ResultExpectation::ASSERT_UPDATE; + case 'watch': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + default: throw new LogicException('Unsupported collection operation: ' . $this->name); } @@ -795,14 +867,18 @@ private function getResultAssertionTypeForDatabase() case 'aggregate': case 'listCollections': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + case 'listCollectionNames': return ResultExpectation::ASSERT_SAME; + case 'createCollection': case 'dropCollection': case 'runCommand': return ResultExpectation::ASSERT_MATCHES_DOCUMENT; + case 'watch': return ResultExpectation::ASSERT_SAME_DOCUMENTS; + default: throw new LogicException('Unsupported database operation: ' . $this->name); } @@ -815,7 +891,7 @@ private function getResultAssertionTypeForDatabase() * @return array * @throws LogicException if the bulk write request is unsupported */ - private function prepareBulkWriteRequest(stdClass $request) + private function prepareBulkWriteRequest(stdClass $request): array { $args = (array) $request->arguments; @@ -828,8 +904,10 @@ private function prepareBulkWriteRequest(stdClass $request) array_diff_key($args, ['filter' => 1]), ], ]; + case 'insertOne': - return [ 'insertOne' => [ $args['document'] ]]; + return ['insertOne' => [$args['document']]]; + case 'replaceOne': return [ 'replaceOne' => [ @@ -838,6 +916,7 @@ private function prepareBulkWriteRequest(stdClass $request) array_diff_key($args, ['filter' => 1, 'replacement' => 1]), ], ]; + case 'updateMany': case 'updateOne': return [ @@ -847,6 +926,7 @@ private function prepareBulkWriteRequest(stdClass $request) array_diff_key($args, ['filter' => 1, 'update' => 1]), ], ]; + default: throw new LogicException('Unsupported bulk write request: ' . $request->name); } diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php index 60680dc04..36dacd06f 100644 --- a/tests/SpecTests/PrimaryStepDownSpecTest.php +++ b/tests/SpecTests/PrimaryStepDownSpecTest.php @@ -13,6 +13,7 @@ use MongoDB\Operation\BulkWrite; use MongoDB\Tests\CommandObserver; use UnexpectedValueException; + use function current; use function sprintf; @@ -21,9 +22,9 @@ */ class PrimaryStepDownSpecTest extends FunctionalTestCase { - const INTERRUPTED_AT_SHUTDOWN = 11600; - const NOT_PRIMARY = 10107; - const SHUTDOWN_IN_PROGRESS = 91; + public const INTERRUPTED_AT_SHUTDOWN = 11600; + public const NOT_PRIMARY = 10107; + public const SHUTDOWN_IN_PROGRESS = 91; /** @var Client */ private $client; @@ -31,7 +32,7 @@ class PrimaryStepDownSpecTest extends FunctionalTestCase /** @var Collection */ private $collection; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -44,7 +45,7 @@ public function setUp() : void /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id10 */ - public function testNotPrimaryKeepsConnectionPool() + public function testNotPrimaryKeepsConnectionPool(): void { $runOn = [(object) ['minServerVersion' => '4.1.11', 'topology' => [self::TOPOLOGY_REPLICASET]]]; $this->checkServerRequirements($runOn); @@ -80,7 +81,7 @@ public function testNotPrimaryKeepsConnectionPool() /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id11 */ - public function testNotPrimaryResetConnectionPool() + public function testNotPrimaryResetConnectionPool(): void { $runOn = [(object) ['minServerVersion' => '4.0.0', 'maxServerVersion' => '4.0.999', 'topology' => [self::TOPOLOGY_REPLICASET]]]; $this->checkServerRequirements($runOn); @@ -116,7 +117,7 @@ public function testNotPrimaryResetConnectionPool() /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id12 */ - public function testShutdownResetConnectionPool() + public function testShutdownResetConnectionPool(): void { $runOn = [(object) ['minServerVersion' => '4.0.0']]; $this->checkServerRequirements($runOn); @@ -152,7 +153,7 @@ public function testShutdownResetConnectionPool() /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id13 */ - public function testInterruptedAtShutdownResetConnectionPool() + public function testInterruptedAtShutdownResetConnectionPool(): void { $runOn = [(object) ['minServerVersion' => '4.0.0']]; $this->checkServerRequirements($runOn); @@ -188,7 +189,7 @@ public function testInterruptedAtShutdownResetConnectionPool() /** * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id9 */ - public function testGetMoreIteration() + public function testGetMoreIteration(): void { $this->markTestSkipped('Test causes subsequent failures in other tests (see PHPLIB-471)'); @@ -230,10 +231,10 @@ public function testGetMoreIteration() $events = []; $observer = new CommandObserver(); $observer->observe( - function () use ($cursor) { + function () use ($cursor): void { $cursor->next(); }, - function ($event) use (&$events) { + function ($event) use (&$events): void { $events[] = $event; } ); @@ -261,13 +262,13 @@ private function insertDocuments($count) return $this->collection->bulkWrite($operations, ['writeConcern' => new WriteConcern('majority')]); } - private function dropAndRecreateCollection() + private function dropAndRecreateCollection(): void { $this->client->selectCollection($this->getDatabaseName(), $this->getCollectionName())->drop(); $this->client->selectDatabase($this->getDatabaseName())->command(['create' => $this->getCollectionName()]); } - private function getTotalConnectionsCreated(Server $server = null) + private function getTotalConnectionsCreated(?Server $server = null) { $server = $server ?: $this->client->getManager()->selectServer(new ReadPreference('primary')); @@ -287,7 +288,7 @@ private function getTotalConnectionsCreated(Server $server = null) throw new UnexpectedValueException('Could not determine number of total connections'); } - private function waitForPrimaryReelection() + private function waitForPrimaryReelection(): void { try { $this->insertDocuments(1); diff --git a/tests/SpecTests/ReadWriteConcernSpecTest.php b/tests/SpecTests/ReadWriteConcernSpecTest.php index 12f4f624f..199a93ea4 100644 --- a/tests/SpecTests/ReadWriteConcernSpecTest.php +++ b/tests/SpecTests/ReadWriteConcernSpecTest.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\SpecTests; use stdClass; + use function basename; use function dirname; use function file_get_contents; @@ -22,7 +23,7 @@ class ReadWriteConcernSpecTest extends FunctionalTestCase * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { foreach ($expected as $key => $value) { if ($value === null) { @@ -44,7 +45,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testReadWriteConcern(stdClass $test, array $runOn = null, array $data, $databaseName = null, $collectionName = null) + public function testReadWriteConcern(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); @@ -99,8 +100,10 @@ public function provideTests() $group = basename(dirname($filename)) . '/' . basename($filename, '.json'); $runOn = $json->runOn ?? null; $data = $json->data ?? []; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $databaseName = $json->database_name ?? null; $collectionName = $json->collection_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; diff --git a/tests/SpecTests/ResultExpectation.php b/tests/SpecTests/ResultExpectation.php index 199fc0035..96e5640b6 100644 --- a/tests/SpecTests/ResultExpectation.php +++ b/tests/SpecTests/ResultExpectation.php @@ -11,6 +11,7 @@ use MongoDB\InsertOneResult; use MongoDB\UpdateResult; use stdClass; + use function call_user_func; use function is_array; use function is_object; @@ -21,19 +22,19 @@ */ final class ResultExpectation { - const ASSERT_NOTHING = 0; - const ASSERT_BULKWRITE = 1; - const ASSERT_DELETE = 2; - const ASSERT_INSERTMANY = 3; - const ASSERT_INSERTONE = 4; - const ASSERT_UPDATE = 5; - const ASSERT_SAME = 6; - const ASSERT_SAME_DOCUMENT = 7; - const ASSERT_SAME_DOCUMENTS = 8; - const ASSERT_MATCHES_DOCUMENT = 9; - const ASSERT_NULL = 10; - const ASSERT_CALLABLE = 11; - const ASSERT_DOCUMENTS_MATCH = 12; + public const ASSERT_NOTHING = 0; + public const ASSERT_BULKWRITE = 1; + public const ASSERT_DELETE = 2; + public const ASSERT_INSERTMANY = 3; + public const ASSERT_INSERTONE = 4; + public const ASSERT_UPDATE = 5; + public const ASSERT_SAME = 6; + public const ASSERT_SAME_DOCUMENT = 7; + public const ASSERT_SAME_DOCUMENTS = 8; + public const ASSERT_MATCHES_DOCUMENT = 9; + public const ASSERT_NULL = 10; + public const ASSERT_CALLABLE = 11; + public const ASSERT_DOCUMENTS_MATCH = 12; /** @var integer */ private $assertionType = self::ASSERT_NOTHING; @@ -48,7 +49,7 @@ final class ResultExpectation * @param integer $assertionType * @param mixed $expectedValue */ - private function __construct($assertionType, $expectedValue) + private function __construct(int $assertionType, $expectedValue) { switch ($assertionType) { case self::ASSERT_BULKWRITE: @@ -59,12 +60,14 @@ private function __construct($assertionType, $expectedValue) if (! is_object($expectedValue)) { throw InvalidArgumentException::invalidType('$expectedValue', $expectedValue, 'object'); } + break; case self::ASSERT_SAME_DOCUMENTS: if (! self::isArrayOfObjects($expectedValue)) { throw InvalidArgumentException::invalidType('$expectedValue', $expectedValue, 'object[]'); } + break; } @@ -170,7 +173,7 @@ public static function fromTransactions(stdClass $operation, $defaultAssertionTy * @param mixed $result Result (if any) from the actual outcome * @throws LogicException if the assertion type is unsupported */ - public function assert(FunctionalTestCase $test, $actual) + public function assert(FunctionalTestCase $test, $actual): void { $expected = $this->expectedValue; @@ -216,6 +219,7 @@ public function assert(FunctionalTestCase $test, $actual) if (isset($expected->upsertedIds)) { $test->assertSameDocument($expected->upsertedIds, $actual->getUpsertedIds()); } + break; case self::ASSERT_CALLABLE: @@ -228,6 +232,7 @@ public function assert(FunctionalTestCase $test, $actual) if (isset($expected->deletedCount)) { $test->assertSame($expected->deletedCount, $actual->getDeletedCount()); } + break; case self::ASSERT_INSERTMANY: @@ -247,6 +252,7 @@ public function assert(FunctionalTestCase $test, $actual) if (isset($expected->insertedIds) && $actual instanceof BulkWriteResult) { $test->assertSameDocument($expected->insertedIds, $actual->getInsertedIds()); } + break; case self::ASSERT_INSERTONE: @@ -265,6 +271,7 @@ public function assert(FunctionalTestCase $test, $actual) ['insertedId' => $actual->getInsertedId()] ); } + break; case self::ASSERT_MATCHES_DOCUMENT: @@ -325,6 +332,7 @@ public function assert(FunctionalTestCase $test, $actual) ['upsertedId' => $actual->getUpsertedId()] ); } + break; default: @@ -359,7 +367,7 @@ private static function isArrayOfObjects($array) * @param mixed $result * @return boolean */ - private static function isErrorResult($result) + private static function isErrorResult($result): bool { if (! is_object($result)) { return false; diff --git a/tests/SpecTests/RetryableReadsSpecTest.php b/tests/SpecTests/RetryableReadsSpecTest.php index 928ee7957..3f16f4324 100644 --- a/tests/SpecTests/RetryableReadsSpecTest.php +++ b/tests/SpecTests/RetryableReadsSpecTest.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\SpecTests; use stdClass; + use function basename; use function file_get_contents; use function glob; @@ -29,7 +30,7 @@ class RetryableReadsSpecTest extends FunctionalTestCase * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { static::assertDocumentsMatch($expected, $actual); } @@ -48,7 +49,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @group matrix-testing-exclude-server-4.4-driver-4.2 * @group matrix-testing-exclude-server-5.0-driver-4.2 */ - public function testRetryableReads(stdClass $test, array $runOn = null, $data, $databaseName, $collectionName, $bucketName) + public function testRetryableReads(stdClass $test, ?array $runOn = null, $data, string $databaseName, ?string $collectionName, ?string $bucketName): void { if (isset($runOn)) { $this->checkServerRequirements($runOn); @@ -110,9 +111,11 @@ public function provideTests() $group = basename($filename, '.json'); $runOn = $json->runOn ?? null; $data = $json->data ?? []; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $databaseName = $json->database_name ?? null; $collectionName = $json->collection_name ?? null; $bucketName = $json->bucket_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; diff --git a/tests/SpecTests/RetryableWritesSpecTest.php b/tests/SpecTests/RetryableWritesSpecTest.php index 5d41a752f..8f9ffaf97 100644 --- a/tests/SpecTests/RetryableWritesSpecTest.php +++ b/tests/SpecTests/RetryableWritesSpecTest.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\SpecTests; use stdClass; + use function basename; use function file_get_contents; use function glob; @@ -22,7 +23,7 @@ class RetryableWritesSpecTest extends FunctionalTestCase * @param array $runOn Top-level "runOn" array with server requirements * @param array $data Top-level "data" array to initialize collection */ - public function testRetryableWrites(stdClass $test, array $runOn = null, array $data) + public function testRetryableWrites(stdClass $test, ?array $runOn = null, array $data): void { if ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('Transaction numbers are only allowed on a replica set member or mongos (PHPC-1415)'); diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 0b2b67595..1829ed6a1 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -9,6 +9,7 @@ use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use stdClass; + use function array_unique; use function basename; use function count; @@ -24,7 +25,7 @@ */ class TransactionsSpecTest extends FunctionalTestCase { - const INTERRUPTED = 11601; + public const INTERRUPTED = 11601; /** * In addition to the useMultipleMongoses tests, these should all pass @@ -38,7 +39,7 @@ class TransactionsSpecTest extends FunctionalTestCase 'transactions/pin-mongos: unpin after transient error within a transaction and commit' => 'isMaster failpoints cannot be disabled', ]; - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -47,7 +48,7 @@ public function setUp() : void $this->skipIfTransactionsAreNotSupported(); } - public function tearDown() : void + public function tearDown(): void { if ($this->hasFailed()) { static::killAllSessions(); @@ -64,7 +65,7 @@ public function tearDown() : void * @param stdClass $expected Expected command document * @param stdClass $actual Actual command document */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual) + public static function assertCommandMatches(stdClass $expected, stdClass $actual): void { if (isset($expected->getMore) && $expected->getMore === 42) { static::assertObjectHasAttribute('getMore', $actual); @@ -119,7 +120,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testTransactions(stdClass $test, array $runOn = null, array $data, $databaseName = null, $collectionName = null) + public function testTransactions(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); @@ -181,8 +182,10 @@ public function provideTests() $group = basename(dirname($filename)) . '/' . basename($filename, '.json'); $runOn = $json->runOn ?? null; $data = $json->data ?? []; + // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $databaseName = $json->database_name ?? null; $collectionName = $json->collection_name ?? null; + // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; @@ -198,7 +201,7 @@ public function provideTests() * ClientSession unpins the session and normal server selection is performed * for the next operation. */ - public function testStartingNewTransactionOnPinnedSessionUnpinsSession() + public function testStartingNewTransactionOnPinnedSessionUnpinsSession(): void { if (! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('Mongos pinning tests can only run on sharded clusters using replica sets'); @@ -236,7 +239,7 @@ public function testStartingNewTransactionOnPinnedSessionUnpinsSession() * ClientSession unpins the session and normal server selection is * performed. */ - public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession() + public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession(): void { if (! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('Mongos pinning tests can only run on sharded clusters using replica sets'); @@ -270,7 +273,7 @@ public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession() /** * Create the collection, since it cannot be created within a transaction. */ - protected function createTestCollection() + protected function createTestCollection(): void { $context = $this->getContext(); @@ -285,7 +288,7 @@ protected function createTestCollection() * previously failed test. For sharded clusters, this command will be run * on all mongos nodes. */ - private static function killAllSessions() + private static function killAllSessions(): void { $manager = static::createTestManager(); $primary = $manager->selectServer(new ReadPreference('primary')); @@ -300,6 +303,7 @@ private static function killAllSessions() if (! isset($server->getInfo()['logicalSessionTimeoutMinutes'])) { continue; } + $server->executeCommand('admin', new Command(['killAllSessions' => []])); } catch (ServerException $e) { // Interrupted error is safe to ignore (see: SERVER-38335) @@ -316,7 +320,7 @@ private static function killAllSessions() * @param array $operations * @see https://github.com/mongodb/specifications/tree/master/source/transactions/tests#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversionts. */ - private function preventStaleDbVersionError(array $operations) + private function preventStaleDbVersionError(array $operations): void { if (! $this->isShardedCluster()) { return; diff --git a/tests/TestCase.php b/tests/TestCase.php index 16e50da1e..133d9699f 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -12,6 +12,7 @@ use ReflectionClass; use stdClass; use Traversable; + use function array_map; use function array_merge; use function array_values; @@ -27,6 +28,7 @@ use function restore_error_handler; use function set_error_handler; use function sprintf; + use const E_USER_DEPRECATED; abstract class TestCase extends BaseTestCase @@ -36,7 +38,7 @@ abstract class TestCase extends BaseTestCase * * @return string */ - public static function getUri() + public static function getUri(): string { return getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1:27017'; } @@ -50,7 +52,7 @@ public static function getUri() * @param array|object $expectedDocument * @param array|object $actualDocument */ - public function assertMatchesDocument($expectedDocument, $actualDocument) + public function assertMatchesDocument($expectedDocument, $actualDocument): void { $normalizedExpectedDocument = $this->normalizeBSON($expectedDocument); $normalizedActualDocument = $this->normalizeBSON($actualDocument); @@ -84,7 +86,7 @@ public function assertMatchesDocument($expectedDocument, $actualDocument) * @param array|object $expectedDocument * @param array|object $actualDocument */ - public function assertSameDocument($expectedDocument, $actualDocument) + public function assertSameDocument($expectedDocument, $actualDocument): void { $this->assertEquals( toJSON(fromPHP($this->normalizeBSON($expectedDocument))), @@ -92,7 +94,7 @@ public function assertSameDocument($expectedDocument, $actualDocument) ); } - public function assertSameDocuments(array $expectedDocuments, $actualDocuments) + public function assertSameDocuments(array $expectedDocuments, $actualDocuments): void { if ($actualDocuments instanceof Traversable) { $actualDocuments = iterator_to_array($actualDocuments); @@ -115,7 +117,7 @@ public function assertSameDocuments(array $expectedDocuments, $actualDocuments) /** * Compatibility method as PHPUnit 9 no longer includes this method. */ - public function dataDescription() : string + public function dataDescription(): string { $dataName = $this->dataName(); @@ -132,11 +134,11 @@ public function provideInvalidDocumentValues() return $this->wrapValuesForDataProvider($this->getInvalidDocumentValues()); } - protected function assertDeprecated(callable $execution) + protected function assertDeprecated(callable $execution): void { $errors = []; - set_error_handler(function ($errno, $errstr) use (&$errors) { + set_error_handler(function ($errno, $errstr) use (&$errors): void { $errors[] = $errstr; }, E_USER_DEPRECATED); @@ -154,7 +156,7 @@ protected function assertDeprecated(callable $execution) * * @return string */ - protected function getCollectionName() + protected function getCollectionName(): string { $class = new ReflectionClass($this); @@ -166,7 +168,7 @@ protected function getCollectionName() * * @return string */ - protected function getDatabaseName() + protected function getDatabaseName(): string { return getenv('MONGODB_DATABASE') ?: 'phplib_test'; } @@ -178,7 +180,7 @@ protected function getDatabaseName() * * @return array */ - protected function getInvalidArrayValues($includeNull = false) + protected function getInvalidArrayValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', true, new stdClass()], $includeNull ? [null] : []); } @@ -190,7 +192,7 @@ protected function getInvalidArrayValues($includeNull = false) * * @return array */ - protected function getInvalidBooleanValues($includeNull = false) + protected function getInvalidBooleanValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', [], new stdClass()], $includeNull ? [null] : []); } @@ -202,7 +204,7 @@ protected function getInvalidBooleanValues($includeNull = false) * * @return array */ - protected function getInvalidDocumentValues($includeNull = false) + protected function getInvalidDocumentValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', true], $includeNull ? [null] : []); } @@ -214,7 +216,7 @@ protected function getInvalidDocumentValues($includeNull = false) * * @return array */ - protected function getInvalidIntegerValues($includeNull = false) + protected function getInvalidIntegerValues(bool $includeNull = false): array { return array_merge([3.14, 'foo', true, [], new stdClass()], $includeNull ? [null] : []); } @@ -226,7 +228,7 @@ protected function getInvalidIntegerValues($includeNull = false) * * @return array */ - protected function getInvalidReadConcernValues($includeNull = false) + protected function getInvalidReadConcernValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []); } @@ -238,7 +240,7 @@ protected function getInvalidReadConcernValues($includeNull = false) * * @return array */ - protected function getInvalidReadPreferenceValues($includeNull = false) + protected function getInvalidReadPreferenceValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new WriteConcern(1)], $includeNull ? [null] : []); } @@ -250,7 +252,7 @@ protected function getInvalidReadPreferenceValues($includeNull = false) * * @return array */ - protected function getInvalidSessionValues($includeNull = false) + protected function getInvalidSessionValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []); } @@ -262,7 +264,7 @@ protected function getInvalidSessionValues($includeNull = false) * * @return array */ - protected function getInvalidStringValues($includeNull = false) + protected function getInvalidStringValues(bool $includeNull = false): array { return array_merge([123, 3.14, true, [], new stdClass()], $includeNull ? [null] : []); } @@ -274,7 +276,7 @@ protected function getInvalidStringValues($includeNull = false) * * @return array */ - protected function getInvalidWriteConcernValues($includeNull = false) + protected function getInvalidWriteConcernValues(bool $includeNull = false): array { return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::RP_PRIMARY)], $includeNull ? [null] : []); } @@ -284,7 +286,7 @@ protected function getInvalidWriteConcernValues($includeNull = false) * * @return string */ - protected function getNamespace() + protected function getNamespace(): string { return sprintf('%s.%s', $this->getDatabaseName(), $this->getCollectionName()); } @@ -295,7 +297,7 @@ protected function getNamespace() * @param array $values List of values * @return array */ - protected function wrapValuesForDataProvider(array $values) + protected function wrapValuesForDataProvider(array $values): array { return array_map(function ($value) { return [$value]; diff --git a/tests/UnifiedSpecTests/CollectionData.php b/tests/UnifiedSpecTests/CollectionData.php index 33f0cea46..46d7e2ec2 100644 --- a/tests/UnifiedSpecTests/CollectionData.php +++ b/tests/UnifiedSpecTests/CollectionData.php @@ -10,6 +10,7 @@ use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use MultipleIterator; use stdClass; + use function PHPUnit\Framework\assertContainsOnly; use function PHPUnit\Framework\assertIsArray; use function PHPUnit\Framework\assertIsString; @@ -41,7 +42,7 @@ public function __construct(stdClass $o) $this->documents = $o->documents; } - public function prepareInitialData(Client $client) + public function prepareInitialData(Client $client): void { $database = $client->selectDatabase( $this->databaseName, @@ -59,7 +60,7 @@ public function prepareInitialData(Client $client) $database->selectCollection($this->collectionName)->insertMany($this->documents); } - public function assertOutcome(Client $client) + public function assertOutcome(Client $client): void { $collection = $client->selectCollection( $this->databaseName, @@ -77,7 +78,7 @@ public function assertOutcome(Client $client) $mi->attachIterator($cursor); foreach ($mi as $i => $documents) { - list($expectedDocument, $actualDocument) = $documents; + [$expectedDocument, $actualDocument] = $documents; assertNotNull($expectedDocument); assertNotNull($actualDocument); diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonType.php b/tests/UnifiedSpecTests/Constraint/IsBsonType.php index 76dbe4278..8d07a250f 100644 --- a/tests/UnifiedSpecTests/Constraint/IsBsonType.php +++ b/tests/UnifiedSpecTests/Constraint/IsBsonType.php @@ -24,6 +24,7 @@ use PHPUnit\Framework\Constraint\LogicalOr; use RuntimeException; use Symfony\Bridge\PhpUnit\ConstraintTrait; + use function array_keys; use function array_map; use function count; @@ -36,6 +37,7 @@ use function is_string; use function range; use function sprintf; + use const PHP_INT_SIZE; final class IsBsonType extends Constraint @@ -79,12 +81,12 @@ public function __construct(string $type) $this->type = $type; } - public static function any() : LogicalOr + public static function any(): LogicalOr { return self::anyOf(...self::$types); } - public static function anyOf(string ...$types) : Constraint + public static function anyOf(string ...$types): Constraint { if (count($types) === 1) { return new self(...$types); @@ -95,67 +97,88 @@ public static function anyOf(string ...$types) : Constraint }, $types)); } - private function doMatches($other) : bool + private function doMatches($other): bool { switch ($this->type) { case 'double': return is_float($other); + case 'string': return is_string($other); + case 'object': return self::isObject($other); + case 'array': return self::isArray($other); + case 'binData': return $other instanceof BinaryInterface; + case 'undefined': return $other instanceof Undefined; + case 'objectId': return $other instanceof ObjectIdInterface; + case 'bool': return is_bool($other); + case 'date': return $other instanceof UTCDateTimeInterface; + case 'null': return $other === null; + case 'regex': return $other instanceof RegexInterface; + case 'dbPointer': return $other instanceof DBPointer; + case 'javascript': return $other instanceof JavascriptInterface && $other->getScope() === null; + case 'symbol': return $other instanceof Symbol; + case 'javascriptWithScope': return $other instanceof JavascriptInterface && $other->getScope() !== null; + case 'int': return is_int($other); + case 'timestamp': return $other instanceof TimestampInterface; + case 'long': if (PHP_INT_SIZE == 4) { return $other instanceof Int64; } return is_int($other); + case 'decimal': return $other instanceof Decimal128Interface; + case 'minKey': return $other instanceof MinKeyInterface; + case 'maxKey': return $other instanceof MaxKeyInterface; + default: // This should already have been caught in the constructor throw new LogicException('Unsupported type: ' . $this->type); } } - private function doToString() : string + private function doToString(): string { return sprintf('is of BSON type "%s"', $this->type); } - private static function isArray($other) : bool + private static function isArray($other): bool { if ($other instanceof BSONArray) { return true; @@ -174,7 +197,7 @@ private static function isArray($other) : bool return self::isArrayEmptyOrIndexed($other); } - private static function isObject($other) : bool + private static function isObject($other): bool { if ($other instanceof BSONDocument) { return true; @@ -199,7 +222,7 @@ private static function isObject($other) : bool return ! $other instanceof Type; } - private static function isArrayEmptyOrIndexed(array $a) : bool + private static function isArrayEmptyOrIndexed(array $a): bool { if (empty($a)) { return true; diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php index 302e63c3b..69564af87 100644 --- a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php +++ b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php @@ -18,10 +18,12 @@ use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\ExpectationFailedException; use stdClass; + use function fopen; use function MongoDB\BSON\fromJSON; use function MongoDB\BSON\toPHP; use function unserialize; + use const PHP_INT_SIZE; class IsBsonTypeTest extends TestCase @@ -29,7 +31,7 @@ class IsBsonTypeTest extends TestCase /** * @dataProvider provideTypes */ - public function testConstraint($type, $value) + public function testConstraint($type, $value): void { $this->assertResult(true, new IsBsonType($type), $value, $this->dataName() . ' is ' . $type); } @@ -72,17 +74,17 @@ public function provideTypes() /** * @dataProvider provideTypes */ - public function testAny($type, $value) + public function testAny($type, $value): void { $this->assertResult(true, IsBsonType::any(), $value, $this->dataName() . ' is a BSON type'); } - public function testAnyExcludesStream() + public function testAnyExcludesStream(): void { $this->assertResult(false, IsBsonType::any(), fopen('php://temp', 'w+b'), 'stream is not a BSON type'); } - public function testAnyOf() + public function testAnyOf(): void { $c = IsBsonType::anyOf('double', 'int'); @@ -91,7 +93,7 @@ public function testAnyOf() $this->assertResult(false, $c, 'foo', 'string is not double or int'); } - public function testErrorMessage() + public function testErrorMessage(): void { $c = new IsBsonType('string'); @@ -103,7 +105,7 @@ public function testErrorMessage() } } - public function testTypeArray() + public function testTypeArray(): void { $c = new IsBsonType('array'); @@ -118,7 +120,7 @@ public function testTypeArray() $this->assertResult(false, $c, new SerializableObject(), 'SerializableObject is not array'); } - public function testTypeObject() + public function testTypeObject(): void { $c = new IsBsonType('object'); @@ -135,7 +137,7 @@ public function testTypeObject() $this->assertResult(false, $c, new ObjectId(), 'Type other than Serializable is not object'); } - public function testTypeJavascript() + public function testTypeJavascript(): void { $c = new IsBsonType('javascript'); @@ -143,7 +145,7 @@ public function testTypeJavascript() $this->assertResult(false, $c, new Javascript('foo = 1;', ['x' => 1]), 'javascriptWithScope is not javascript'); } - public function testTypeJavascriptWithScope() + public function testTypeJavascriptWithScope(): void { $c = new IsBsonType('javascriptWithScope'); @@ -151,7 +153,7 @@ public function testTypeJavascriptWithScope() $this->assertResult(false, $c, new Javascript('foo = 1;'), 'javascript is not javascriptWithScope'); } - private function assertResult($expected, Constraint $constraint, $value, string $message = '') + private function assertResult($expected, Constraint $constraint, $value, string $message = ''): void { $this->assertSame($expected, $constraint->evaluate($value, '', true), $message); } diff --git a/tests/UnifiedSpecTests/Constraint/Matches.php b/tests/UnifiedSpecTests/Constraint/Matches.php index 78bd504c4..4704519cf 100644 --- a/tests/UnifiedSpecTests/Constraint/Matches.php +++ b/tests/UnifiedSpecTests/Constraint/Matches.php @@ -14,6 +14,7 @@ use SebastianBergmann\Comparator\ComparisonFailure; use SebastianBergmann\Comparator\Factory; use Symfony\Bridge\PhpUnit\ConstraintTrait; + use function array_keys; use function count; use function get_debug_type; @@ -36,6 +37,7 @@ use function range; use function sprintf; use function strpos; + use const PHP_INT_SIZE; /** @@ -64,7 +66,7 @@ class Matches extends Constraint /** @var ComparisonFailure|null */ private $lastFailure; - public function __construct($value, EntityMap $entityMap = null, $allowExtraRootKeys = true, $allowOperators = true) + public function __construct($value, ?EntityMap $entityMap = null, $allowExtraRootKeys = true, $allowOperators = true) { $this->value = self::prepare($value); $this->entityMap = $entityMap; @@ -110,7 +112,7 @@ private function doEvaluate($other, $description = '', $returnResult = false) } } - private function assertEquals($expected, $actual, string $keyPath) + private function assertEquals($expected, $actual, string $keyPath): void { $expectedType = get_debug_type($expected); $actualType = get_debug_type($actual); @@ -131,7 +133,7 @@ private function assertEquals($expected, $actual, string $keyPath) } } - private function assertMatches($expected, $actual, string $keyPath = '') + private function assertMatches($expected, $actual, string $keyPath = ''): void { if ($expected instanceof BSONArray) { $this->assertMatchesArray($expected, $actual, $keyPath); @@ -148,7 +150,7 @@ private function assertMatches($expected, $actual, string $keyPath = '') $this->assertEquals($expected, $actual, $keyPath); } - private function assertMatchesArray(BSONArray $expected, $actual, string $keyPath) + private function assertMatchesArray(BSONArray $expected, $actual, string $keyPath): void { if (! $actual instanceof BSONArray) { $actualType = get_debug_type($actual); @@ -168,7 +170,7 @@ private function assertMatchesArray(BSONArray $expected, $actual, string $keyPat } } - private function assertMatchesDocument(BSONDocument $expected, $actual, string $keyPath) + private function assertMatchesDocument(BSONDocument $expected, $actual, string $keyPath): void { if ($this->allowOperators && self::isOperator($expected)) { $this->assertMatchesOperator($expected, $actual, $keyPath); @@ -226,6 +228,7 @@ private function assertMatchesDocument(BSONDocument $expected, $actual, string $ return; } + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps foreach ($actual as $key => $_) { if (! $expected->offsetExists($key)) { self::failAt(sprintf('$actual has unexpected key "%s"', $key), $keyPath); @@ -233,7 +236,7 @@ private function assertMatchesDocument(BSONDocument $expected, $actual, string $ } } - private function assertMatchesOperator(BSONDocument $operator, $actual, string $keyPath) + private function assertMatchesOperator(BSONDocument $operator, $actual, string $keyPath): void { $name = self::getOperatorName($operator); @@ -347,15 +350,16 @@ private function doToString() return 'matches ' . $this->exporter()->export($this->value); } - private static function failAt(string $message, string $keyPath) + private static function failAt(string $message, string $keyPath): void { $prefix = empty($keyPath) ? '' : sprintf('Field path "%s": ', $keyPath); throw new RuntimeException($prefix . $message); } - private static function getOperatorName(BSONDocument $document) : string + private static function getOperatorName(BSONDocument $document): string { + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps foreach ($document as $key => $_) { if (strpos((string) $key, '$$') === 0) { return $key; @@ -370,12 +374,13 @@ private static function isNumeric($value) return is_int($value) || is_float($value) || $value instanceof Int64; } - private static function isOperator(BSONDocument $document) : bool + private static function isOperator(BSONDocument $document): bool { if (count($document) !== 1) { return false; } + // phpcs:ignore Squiz.NamingConventions.ValidVariableName.NotCamelCaps foreach ($document as $key => $_) { return strpos((string) $key, '$$') === 0; } @@ -442,7 +447,7 @@ private static function prepare($bson) return $bson; } - private static function isArrayEmptyOrIndexed(array $a) : bool + private static function isArrayEmptyOrIndexed(array $a): bool { if (empty($a)) { return true; diff --git a/tests/UnifiedSpecTests/Constraint/MatchesTest.php b/tests/UnifiedSpecTests/Constraint/MatchesTest.php index 397894011..c182b2ece 100644 --- a/tests/UnifiedSpecTests/Constraint/MatchesTest.php +++ b/tests/UnifiedSpecTests/Constraint/MatchesTest.php @@ -7,13 +7,14 @@ use MongoDB\Tests\UnifiedSpecTests\EntityMap; use PHPUnit\Framework\ExpectationFailedException; use stdClass; + use function hex2bin; use function preg_quote; use function version_compare; class MatchesTest extends FunctionalTestCase { - public function testMatchesDocument() + public function testMatchesDocument(): void { $c = new Matches(['x' => 1, 'y' => ['a' => 1, 'b' => 2]]); $this->assertResult(false, $c, ['x' => 1, 'y' => 2], 'Incorrect value'); @@ -23,20 +24,20 @@ public function testMatchesDocument() $this->assertResult(true, $c, ['y' => ['b' => 2, 'a' => 1], 'x' => 1], 'Root and embedded key order is not significant'); } - public function testDoNotAllowExtraRootKeys() + public function testDoNotAllowExtraRootKeys(): void { $c = new Matches(['x' => 1], null, false); $this->assertResult(false, $c, ['x' => 1, 'y' => 1], 'Extra keys in root are prohibited'); } - public function testDoNotAllowOperators() + public function testDoNotAllowOperators(): void { $c = new Matches(['x' => ['$$exists' => true]], null, true, false); $this->assertResult(false, $c, ['x' => 1], 'Operators are not processed'); $this->assertResult(true, $c, ['x' => ['$$exists' => true]], 'Operators are not processed but compared as-is'); } - public function testOperatorExists() + public function testOperatorExists(): void { $c = new Matches(['x' => ['$$exists' => true]]); $this->assertResult(true, $c, ['x' => '1'], 'root-level key exists'); @@ -59,7 +60,7 @@ public function testOperatorExists() $this->assertResult(true, $c, ['x' => new stdClass()], 'embedded key missing'); } - public function testOperatorType() + public function testOperatorType(): void { $c = new Matches(['x' => ['$$type' => 'string']]); $this->assertResult(true, $c, ['x' => 'foo'], 'string matches string type'); @@ -71,7 +72,7 @@ public function testOperatorType() $this->assertResult(false, $c, ['x' => 1], 'integer does not match [string,bool] type'); } - public function testOperatorMatchesEntity() + public function testOperatorMatchesEntity(): void { $entityMap = new EntityMap(); $entityMap->set('integer', 1); @@ -93,7 +94,7 @@ public function testOperatorMatchesEntity() $this->assertResult(false, $c, ['x' => ['y' => 1, 'z' => 2]], 'value does not match object entity (root-level)'); } - public function testOperatorMatchesHexBytes() + public function testOperatorMatchesHexBytes(): void { $c = new Matches(['$$matchesHexBytes' => 'DEADBEEF']); $this->assertResult(true, $c, hex2bin('DEADBEEF'), 'value matches hex bytes (root-level)'); @@ -104,7 +105,7 @@ public function testOperatorMatchesHexBytes() $this->assertResult(false, $c, ['x' => hex2bin('DEADBEEF')], 'value does not match hex bytes (embedded)'); } - public function testOperatorUnsetOrMatches() + public function testOperatorUnsetOrMatches(): void { $c = new Matches(['$$unsetOrMatches' => ['x' => 1]]); $this->assertResult(true, $c, null, 'null value is considered unset (root-level)'); @@ -119,7 +120,7 @@ public function testOperatorUnsetOrMatches() $this->assertResult(false, $c, ['x' => ['y' => 1, 'z' => 2]], 'value does not match (embedded)'); } - public function testOperatorSessionLsid() + public function testOperatorSessionLsid(): void { if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { $this->markTestSkipped('startSession() is only supported on FCV 3.6 or higher'); @@ -149,7 +150,7 @@ public function testOperatorSessionLsid() /** * @dataProvider errorMessageProvider */ - public function testErrorMessages($expectedMessageRegex, Matches $constraint, $actualValue) + public function testErrorMessages($expectedMessageRegex, Matches $constraint, $actualValue): void { try { $constraint->evaluate($actualValue); @@ -234,7 +235,7 @@ public function errorMessageProvider() /** * @dataProvider operatorErrorMessageProvider */ - public function testOperatorSyntaxValidation($expectedMessage, Matches $constraint) + public function testOperatorSyntaxValidation($expectedMessage, Matches $constraint): void { $this->expectException(ExpectationFailedException::class); $this->expectExceptionMessage($expectedMessage); @@ -284,7 +285,7 @@ public function operatorErrorMessageProvider() ]; } - private function assertResult($expected, Matches $constraint, $value, string $message = '') + private function assertResult($expected, Matches $constraint, $value, string $message = ''): void { $this->assertSame($expected, $constraint->evaluate($value, '', true), $message); } diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 82712e559..b037a7eff 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -10,6 +10,7 @@ use MongoDB\Model\BSONArray; use MongoDB\Tests\FunctionalTestCase; use stdClass; + use function array_key_exists; use function array_map; use function count; @@ -35,6 +36,7 @@ use function strlen; use function strpos; use function substr_replace; + use const PHP_URL_HOST; /** @@ -81,7 +83,7 @@ public function __construct(Client $internalClient, string $uri) * * @param array $createEntities */ - public function createEntities(array $entities) + public function createEntities(array $entities): void { foreach ($entities as $entity) { assertIsObject($entity); @@ -122,22 +124,22 @@ public function createEntities(array $entities) } } - public function getEntityMap() : EntityMap + public function getEntityMap(): EntityMap { return $this->entityMap; } - public function getInternalClient() : Client + public function getInternalClient(): Client { return $this->internalClient; } - public function isDirtySession(string $sessionId) : bool + public function isDirtySession(string $sessionId): bool { return in_array($sessionId, $this->dirtySessions); } - public function markDirtySession(string $sessionId) + public function markDirtySession(string $sessionId): void { if ($this->isDirtySession($sessionId)) { return; @@ -146,27 +148,27 @@ public function markDirtySession(string $sessionId) $this->dirtySessions[] = $sessionId; } - public function isActiveClient(string $clientId) : bool + public function isActiveClient(string $clientId): bool { return $this->activeClient === $clientId; } - public function setActiveClient(string $clientId = null) + public function setActiveClient(?string $clientId = null): void { $this->activeClient = $clientId; } - public function isInLoop() : bool + public function isInLoop(): bool { return $this->inLoop; } - public function setInLoop(bool $inLoop) + public function setInLoop(bool $inLoop): void { $this->inLoop = $inLoop; } - public function assertExpectedEventsForClients(array $expectedEventsForClients) + public function assertExpectedEventsForClients(array $expectedEventsForClients): void { assertNotEmpty($expectedEventsForClients); @@ -189,35 +191,35 @@ public function assertExpectedEventsForClients(array $expectedEventsForClients) } } - public function startEventObservers() + public function startEventObservers(): void { foreach ($this->eventObserversByClient as $eventObserver) { $eventObserver->start(); } } - public function stopEventObservers() + public function stopEventObservers(): void { foreach ($this->eventObserversByClient as $eventObserver) { $eventObserver->stop(); } } - public function getEventObserverForClient(string $id) : EventObserver + public function getEventObserverForClient(string $id): EventObserver { assertArrayHasKey($id, $this->eventObserversByClient); return $this->eventObserversByClient[$id]; } - public function startEventCollectors() + public function startEventCollectors(): void { foreach ($this->eventCollectors as $eventCollector) { $eventCollector->start(); } } - public function stopEventCollectors() + public function stopEventCollectors(): void { foreach ($this->eventCollectors as $eventCollector) { $eventCollector->stop(); @@ -225,15 +227,15 @@ public function stopEventCollectors() } /** @param string|array $readPreferenceTags */ - private function convertReadPreferenceTags($readPreferenceTags) : array + private function convertReadPreferenceTags($readPreferenceTags): array { return array_map( - static function (string $readPreferenceTagSet) : array { + static function (string $readPreferenceTagSet): array { $tags = explode(',', $readPreferenceTagSet); return array_map( - static function (string $tag) : array { - list($key, $value) = explode(':', $tag); + static function (string $tag): array { + [$key, $value] = explode(':', $tag); return [$key => $value]; }, @@ -244,7 +246,7 @@ static function (string $tag) : array { ); } - private function createClient(string $id, stdClass $o) + private function createClient(string $id, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents', 'serverApi', 'storeEventsAsEntities']); @@ -316,7 +318,7 @@ private function createClient(string $id, stdClass $o) $this->entityMap->set($id, FunctionalTestCase::createTestClient($uri, $uriOptions, $driverOptions)); } - private function createEntityCollector(string $clientId, stdClass $o) + private function createEntityCollector(string $clientId, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'events']); @@ -331,7 +333,7 @@ private function createEntityCollector(string $clientId, stdClass $o) $this->eventCollectors[] = new EventCollector($eventList, $events, $clientId, $this); } - private function createCollection(string $id, stdClass $o) + private function createCollection(string $id, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'database', 'collectionName', 'collectionOptions']); @@ -353,7 +355,7 @@ private function createCollection(string $id, stdClass $o) $this->entityMap->set($id, $database->selectCollection($o->collectionName, $options), $databaseId); } - private function createDatabase(string $id, stdClass $o) + private function createDatabase(string $id, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'client', 'databaseName', 'databaseOptions']); @@ -375,7 +377,7 @@ private function createDatabase(string $id, stdClass $o) $this->entityMap->set($id, $client->selectDatabase($databaseName, $options), $clientId); } - private function createSession(string $id, stdClass $o) + private function createSession(string $id, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'client', 'sessionOptions']); @@ -393,7 +395,7 @@ private function createSession(string $id, stdClass $o) $this->entityMap->set($id, $client->startSession($options), $clientId); } - private function createBucket(string $id, stdClass $o) + private function createBucket(string $id, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'database', 'bucketOptions']); @@ -411,14 +413,14 @@ private function createBucket(string $id, stdClass $o) $this->entityMap->set($id, $database->selectGridFSBucket($options), $databaseId); } - private static function prepareCollectionOrDatabaseOptions(array $options) : array + private static function prepareCollectionOrDatabaseOptions(array $options): array { Util::assertHasOnlyKeys($options, ['readConcern', 'readPreference', 'writeConcern']); return Util::prepareCommonOptions($options); } - private static function prepareBucketOptions(array $options) : array + private static function prepareBucketOptions(array $options): array { Util::assertHasOnlyKeys($options, ['bucketName', 'chunkSizeBytes', 'disableMD5', 'readConcern', 'readPreference', 'writeConcern']); @@ -437,7 +439,7 @@ private static function prepareBucketOptions(array $options) : array return Util::prepareCommonOptions($options); } - private static function prepareSessionOptions(array $options) : array + private static function prepareSessionOptions(array $options): array { Util::assertHasOnlyKeys($options, ['causalConsistency', 'defaultTransactionOptions']); @@ -453,7 +455,7 @@ private static function prepareSessionOptions(array $options) : array return $options; } - private static function prepareDefaultTransactionOptions(array $options) : array + private static function prepareDefaultTransactionOptions(array $options): array { Util::assertHasOnlyKeys($options, ['maxCommitTimeMS', 'readConcern', 'readPreference', 'writeConcern']); @@ -468,7 +470,7 @@ private static function prepareDefaultTransactionOptions(array $options) : array * Removes mongos hosts beyond the first if the URI refers to a sharded * cluster. Otherwise, the URI is returned as-is. */ - private static function removeMultipleMongoses(string $uri) : string + private static function removeMultipleMongoses(string $uri): string { assertStringStartsWith('mongodb://', $uri); @@ -508,7 +510,7 @@ private static function removeMultipleMongoses(string $uri) : string /** * Requires multiple mongos hosts if the URI refers to a sharded cluster. */ - private static function requireMultipleMongoses(string $uri) + private static function requireMultipleMongoses(string $uri): void { assertStringStartsWith('mongodb://', $uri); diff --git a/tests/UnifiedSpecTests/DirtySessionObserver.php b/tests/UnifiedSpecTests/DirtySessionObserver.php index e69f7e534..928037812 100644 --- a/tests/UnifiedSpecTests/DirtySessionObserver.php +++ b/tests/UnifiedSpecTests/DirtySessionObserver.php @@ -8,6 +8,7 @@ use MongoDB\Driver\Monitoring\CommandSubscriber; use MongoDB\Driver\Monitoring\CommandSucceededEvent; use stdClass; + use function in_array; use function MongoDB\Driver\Monitoring\addSubscriber; use function MongoDB\Driver\Monitoring\removeSubscriber; @@ -38,7 +39,7 @@ public function __construct(stdClass $lsid) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ - public function commandFailed(CommandFailedEvent $event) + public function commandFailed(CommandFailedEvent $event): void { if (! in_array($event->getRequestId(), $this->requestIds)) { return; @@ -52,7 +53,7 @@ public function commandFailed(CommandFailedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ - public function commandStarted(CommandStartedEvent $event) + public function commandStarted(CommandStartedEvent $event): void { if ($this->lsid == ($event->getCommand()->lsid ?? null)) { $this->requestIds[] = $event->getRequestId(); @@ -62,21 +63,21 @@ public function commandStarted(CommandStartedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ - public function commandSucceeded(CommandSucceededEvent $event) + public function commandSucceeded(CommandSucceededEvent $event): void { } - public function observedNetworkError() : bool + public function observedNetworkError(): bool { return $this->observedNetworkError; } - public function start() + public function start(): void { addSubscriber($this); } - public function stop() + public function stop(): void { removeSubscriber($this); } diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php index 8184cbc7f..28be168fe 100644 --- a/tests/UnifiedSpecTests/EntityMap.php +++ b/tests/UnifiedSpecTests/EntityMap.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\Assert; use PHPUnit\Framework\Constraint\Constraint; use stdClass; + use function array_key_exists; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertArrayNotHasKey; @@ -78,7 +79,7 @@ public function offsetGet($id) /** * @see http://php.net/arrayaccess.offsetset */ - public function offsetSet($id, $value) + public function offsetSet($id, $value): void { Assert::fail('Entities can only be set via set()'); } @@ -86,12 +87,12 @@ public function offsetSet($id, $value) /** * @see http://php.net/arrayaccess.offsetunset */ - public function offsetUnset($id) + public function offsetUnset($id): void { Assert::fail('Entities cannot be removed from the map'); } - public function set(string $id, $value, string $parentId = null) + public function set(string $id, $value, ?string $parentId = null): void { assertArrayNotHasKey($id, $this->map, sprintf('Entity already exists for "%s" and cannot be replaced', $id)); assertThat($value, self::isSupportedType()); @@ -110,14 +111,14 @@ public function set(string $id, $value, string $parentId = null) /** @var self */ public $parent; - public function __construct(string $id, $value, self $parent = null) + public function __construct(string $id, $value, ?self $parent = null) { $this->id = $id; $this->value = $value; $this->parent = $parent; } - public function getRoot() : self + public function getRoot(): self { $root = $this; @@ -135,33 +136,33 @@ public function getRoot() : self * * @see Operation::executeForCursor() */ - public function closeCursor(string $cursorId) + public function closeCursor(string $cursorId): void { assertInstanceOf(Cursor::class, $this[$cursorId]); unset($this->map[$cursorId]); } - public function getClient(string $clientId) : Client + public function getClient(string $clientId): Client { return $this[$clientId]; } - public function getCollection(string $collectionId) : Collection + public function getCollection(string $collectionId): Collection { return $this[$collectionId]; } - public function getDatabase(string $databaseId) : Database + public function getDatabase(string $databaseId): Database { return $this[$databaseId]; } - public function getSession(string $sessionId) : Session + public function getSession(string $sessionId): Session { return $this[$sessionId]; } - public function getLogicalSessionId(string $sessionId) : stdClass + public function getLogicalSessionId(string $sessionId): stdClass { return $this->lsidsBySession[$sessionId]; } @@ -173,7 +174,7 @@ public function getRootClientIdOf(string $id) return $root->value instanceof Client ? $root->id : null; } - private static function isSupportedType() : Constraint + private static function isSupportedType(): Constraint { if (self::$isSupportedType === null) { self::$isSupportedType = logicalOr( diff --git a/tests/UnifiedSpecTests/EventCollector.php b/tests/UnifiedSpecTests/EventCollector.php index 3942eb3e8..4259ab182 100644 --- a/tests/UnifiedSpecTests/EventCollector.php +++ b/tests/UnifiedSpecTests/EventCollector.php @@ -7,6 +7,7 @@ use MongoDB\Driver\Monitoring\CommandSubscriber; use MongoDB\Driver\Monitoring\CommandSucceededEvent; use MongoDB\Model\BSONArray; + use function array_filter; use function array_flip; use function get_class; @@ -82,7 +83,7 @@ public function __construct(BSONArray $eventList, array $collectEvents, string $ /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ - public function commandFailed(CommandFailedEvent $event) + public function commandFailed(CommandFailedEvent $event): void { $this->handleCommandMonitoringEvent($event); } @@ -90,7 +91,7 @@ public function commandFailed(CommandFailedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ - public function commandStarted(CommandStartedEvent $event) + public function commandStarted(CommandStartedEvent $event): void { $this->handleCommandMonitoringEvent($event); } @@ -98,23 +99,23 @@ public function commandStarted(CommandStartedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ - public function commandSucceeded(CommandSucceededEvent $event) + public function commandSucceeded(CommandSucceededEvent $event): void { $this->handleCommandMonitoringEvent($event); } - public function start() + public function start(): void { addSubscriber($this); } - public function stop() + public function stop(): void { removeSubscriber($this); } /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ - private function handleCommandMonitoringEvent($event) + private function handleCommandMonitoringEvent($event): void { assertIsObject($event); @@ -155,7 +156,7 @@ private function handleCommandMonitoringEvent($event) } /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ - private static function getConnectionId($event) : string + private static function getConnectionId($event): string { $server = $event->getServer(); @@ -163,7 +164,7 @@ private static function getConnectionId($event) : string } /** @param object $event */ - private static function getEventName($event) : string + private static function getEventName($event): string { static $eventNamesByClass = null; diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index bd7e54d3f..1be557bf7 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -11,6 +11,7 @@ use MultipleIterator; use PHPUnit\Framework\Assert; use stdClass; + use function array_fill_keys; use function array_reverse; use function count; @@ -101,7 +102,7 @@ public function __construct(array $observeEvents, array $ignoreCommands, string /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ - public function commandFailed(CommandFailedEvent $event) + public function commandFailed(CommandFailedEvent $event): void { $this->handleEvent($event); } @@ -109,7 +110,7 @@ public function commandFailed(CommandFailedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ - public function commandStarted(CommandStartedEvent $event) + public function commandStarted(CommandStartedEvent $event): void { $this->handleEvent($event); } @@ -117,22 +118,22 @@ public function commandStarted(CommandStartedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ - public function commandSucceeded(CommandSucceededEvent $event) + public function commandSucceeded(CommandSucceededEvent $event): void { $this->handleEvent($event); } - public function start() + public function start(): void { addSubscriber($this); } - public function stop() + public function stop(): void { removeSubscriber($this); } - public function getLsidsOnLastTwoCommands() : array + public function getLsidsOnLastTwoCommands(): array { $lsids = []; @@ -153,7 +154,7 @@ public function getLsidsOnLastTwoCommands() : array Assert::fail('Not enough CommandStartedEvents observed'); } - public function assert(array $expectedEvents) + public function assert(array $expectedEvents): void { assertCount(count($expectedEvents), $this->actualEvents); @@ -162,7 +163,7 @@ public function assert(array $expectedEvents) $mi->attachIterator(new ArrayIterator($this->actualEvents)); foreach ($mi as $keys => $events) { - list($expectedEvent, $actualEvent) = $events; + [$expectedEvent, $actualEvent] = $events; assertIsObject($expectedEvent); $expectedEvent = (array) $expectedEvent; @@ -188,16 +189,19 @@ private function assertEvent($actual, stdClass $expected, string $message) switch (get_class($actual)) { case CommandStartedEvent::class: return $this->assertCommandStartedEvent($actual, $expected, $message); + case CommandSucceededEvent::class: return $this->assertCommandSucceededEvent($actual, $expected, $message); + case CommandFailedEvent::class: return $this->assertCommandFailedEvent($actual, $expected, $message); + default: Assert::fail($message . ': Unsupported event type: ' . get_class($actual)); } } - private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass $expected, string $message) + private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass $expected, string $message): void { // TODO: Assert hasServiceId (blocked on PHPC-1752) Util::assertHasOnlyKeys($expected, ['command', 'commandName', 'databaseName']); @@ -219,7 +223,7 @@ private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass } } - private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdClass $expected, string $message) + private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdClass $expected, string $message): void { // TODO: Assert hasServiceId (blocked on PHPC-1752) Util::assertHasOnlyKeys($expected, ['reply', 'commandName']); @@ -236,7 +240,7 @@ private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdC } } - private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $expected, string $message) + private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $expected, string $message): void { // TODO: Assert hasServiceId (blocked on PHPC-1752) Util::assertHasOnlyKeys($expected, ['commandName']); @@ -248,7 +252,7 @@ private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $ } /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ - private function handleEvent($event) + private function handleEvent($event): void { if (! $this->context->isActiveClient($this->clientId)) { return; diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index 1f1bfb639..bcad0d22c 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -10,6 +10,7 @@ use PHPUnit\Framework\Assert; use stdClass; use Throwable; + use function get_class; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertContainsOnly; @@ -67,7 +68,7 @@ final class ExpectedError /** @var ExpectedResult|null */ private $expectedResult; - public function __construct(stdClass $o = null, EntityMap $entityMap) + public function __construct(?stdClass $o = null, EntityMap $entityMap) { if ($o === null) { return; @@ -121,7 +122,7 @@ public function __construct(stdClass $o = null, EntityMap $entityMap) * * @param Throwable|null $e Exception (if any) from executing an operation */ - public function assert(Throwable $e = null) + public function assert(?Throwable $e = null): void { if (! $this->isError && $e !== null) { Assert::fail(sprintf("Operation threw unexpected %s: %s\n%s", get_class($e), $e->getMessage(), $e->getTraceAsString())); @@ -175,7 +176,7 @@ public function assert(Throwable $e = null) } } - private function assertCodeName(ServerException $e) + private function assertCodeName(ServerException $e): void { /* BulkWriteException and ExecutionTimeoutException do not expose * codeName. Work around this by translating it to a numeric code. diff --git a/tests/UnifiedSpecTests/ExpectedResult.php b/tests/UnifiedSpecTests/ExpectedResult.php index f51da2e1c..618a2983d 100644 --- a/tests/UnifiedSpecTests/ExpectedResult.php +++ b/tests/UnifiedSpecTests/ExpectedResult.php @@ -10,6 +10,7 @@ use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use MongoDB\UpdateResult; use stdClass; + use function is_object; use function PHPUnit\Framework\assertThat; use function property_exists; @@ -30,7 +31,7 @@ final class ExpectedResult */ private $yieldingEntityId; - public function __construct(stdClass $o, EntityMap $entityMap, string $yieldingEntityId = null) + public function __construct(stdClass $o, EntityMap $entityMap, ?string $yieldingEntityId = null) { if (property_exists($o, 'expectResult')) { $this->constraint = new Matches($o->expectResult, $entityMap); @@ -40,7 +41,7 @@ public function __construct(stdClass $o, EntityMap $entityMap, string $yieldingE $this->yieldingEntityId = $yieldingEntityId; } - public function assert($actual, string $saveResultAsEntity = null) + public function assert($actual, ?string $saveResultAsEntity = null): void { if ($this->constraint === null && $saveResultAsEntity === null) { return; @@ -63,12 +64,14 @@ private static function prepare($value) return $value; } - if ($value instanceof BulkWriteResult || + if ( + $value instanceof BulkWriteResult || $value instanceof WriteResult || $value instanceof DeleteResult || $value instanceof InsertOneResult || $value instanceof InsertManyResult || - $value instanceof UpdateResult) { + $value instanceof UpdateResult + ) { return self::prepareWriteResult($value); } diff --git a/tests/UnifiedSpecTests/FailPointObserver.php b/tests/UnifiedSpecTests/FailPointObserver.php index f7794f7fc..c38854838 100644 --- a/tests/UnifiedSpecTests/FailPointObserver.php +++ b/tests/UnifiedSpecTests/FailPointObserver.php @@ -7,6 +7,7 @@ use MongoDB\Driver\Monitoring\CommandSubscriber; use MongoDB\Driver\Monitoring\CommandSucceededEvent; use MongoDB\Operation\DatabaseCommand; + use function MongoDB\Driver\Monitoring\addSubscriber; use function MongoDB\Driver\Monitoring\removeSubscriber; @@ -18,14 +19,14 @@ class FailPointObserver implements CommandSubscriber /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ - public function commandFailed(CommandFailedEvent $event) + public function commandFailed(CommandFailedEvent $event): void { } /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ - public function commandStarted(CommandStartedEvent $event) + public function commandStarted(CommandStartedEvent $event): void { $command = $event->getCommand(); @@ -43,13 +44,13 @@ public function commandStarted(CommandStartedEvent $event) /** * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ - public function commandSucceeded(CommandSucceededEvent $event) + public function commandSucceeded(CommandSucceededEvent $event): void { } - public function disableFailPoints() + public function disableFailPoints(): void { - foreach ($this->failPointsAndServers as list($failPoint, $server)) { + foreach ($this->failPointsAndServers as [$failPoint, $server]) { $operation = new DatabaseCommand('admin', ['configureFailPoint' => $failPoint, 'mode' => 'off']); $operation->execute($server); } @@ -57,12 +58,12 @@ public function disableFailPoints() $this->failPointsAndServers = []; } - public function start() + public function start(): void { addSubscriber($this); } - public function stop() + public function stop(): void { removeSubscriber($this); } diff --git a/tests/UnifiedSpecTests/Loop.php b/tests/UnifiedSpecTests/Loop.php index 2395034c5..3351e22b8 100644 --- a/tests/UnifiedSpecTests/Loop.php +++ b/tests/UnifiedSpecTests/Loop.php @@ -9,6 +9,7 @@ use PHPUnit\Framework\SkippedTest; use PHPUnit\Framework\Warning; use Throwable; + use function array_key_exists; use function call_user_func; use function microtime; @@ -73,14 +74,14 @@ public function __construct(array $operations, Context $context, array $options $this->numIterationsEntityId = $options['storeIterationsAsEntity'] ?? null; } - public function execute() + public function execute(): void { assertFalse($this->context->isInLoop(), 'Nested loops are unsupported'); $numIterations = 0; $numSuccessfulOperations = 0; - $callback = function () use (&$numSuccessfulOperations) { + $callback = function () use (&$numSuccessfulOperations): void { foreach ($this->operations as $operation) { $operation->assert(); $numSuccessfulOperations++; @@ -128,7 +129,7 @@ public function execute() * * This function is primarily used by the Atlas testing workload executor. */ - public static function allowIteration(bool $allowIteration = true) + public static function allowIteration(bool $allowIteration = true): void { self::$allowIteration = $allowIteration; } @@ -138,14 +139,14 @@ public static function allowIteration(bool $allowIteration = true) * * This can be used to limit CPU usage during workload execution. */ - public static function setSleepUsecBetweenIterations(int $usec) + public static function setSleepUsecBetweenIterations(int $usec): void { assertGreaterThanOrEqual(0, $usec); self::$sleepUsecBetweenIterations = $usec; } - private function handleErrorOrFailure(Throwable $e) + private function handleErrorOrFailure(Throwable $e): void { /* The constructor will either initialize both lists or leave them both * unset. If unset, exceptions should not be logged and instead @@ -165,7 +166,7 @@ private function handleErrorOrFailure(Throwable $e) ]); } - private function initializeListEntity(string $id) : BSONArray + private function initializeListEntity(string $id): BSONArray { $entityMap = $this->context->getEntityMap(); diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 9c169fd60..e22a8bdf3 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -21,6 +21,7 @@ use PHPUnit\Framework\Constraint\IsType; use stdClass; use Throwable; + use function array_diff_key; use function array_key_exists; use function array_map; @@ -60,7 +61,7 @@ final class Operation { - const OBJECT_TEST_RUNNER = 'testRunner'; + public const OBJECT_TEST_RUNNER = 'testRunner'; /** @var bool */ private $isTestRunnerOperation; @@ -94,7 +95,7 @@ final class Operation public function __construct(stdClass $o, Context $context) { - $this->context =$context; + $this->context = $context; $this->entityMap = $context->getEntityMap(); assertIsString($o->name); @@ -130,7 +131,7 @@ public function __construct(stdClass $o, Context $context) /** * Execute the operation and assert its outcome. */ - public function assert(bool $rethrowExceptions = false) + public function assert(bool $rethrowExceptions = false): void { $error = null; $result = null; @@ -250,6 +251,7 @@ private function executeForChangeStream(ChangeStream $changeStream) } while (! $changeStream->valid()); return $changeStream->current(); + default: Assert::fail('Unsupported change stream operation: ' . $this->name); } @@ -268,10 +270,13 @@ private function executeForClient(Client $client) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); + case 'listDatabaseNames': return iterator_to_array($client->listDatabaseNames($args)); + case 'listDatabases': return iterator_to_array($client->listDatabases($args)); + default: Assert::fail('Unsupported client operation: ' . $this->name); } @@ -290,6 +295,7 @@ private function executeForCollection(Collection $collection) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) )); + case 'bulkWrite': assertArrayHasKey('requests', $args); assertIsArray($args['requests']); @@ -298,6 +304,7 @@ private function executeForCollection(Collection $collection) array_map('self::prepareBulkWriteRequest', $args['requests']), array_diff_key($args, ['requests' => 1]) ); + case 'createChangeStream': assertArrayHasKey('pipeline', $args); assertIsArray($args['pipeline']); @@ -306,6 +313,7 @@ private function executeForCollection(Collection $collection) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); + case 'createFindCursor': assertArrayHasKey('filter', $args); assertInstanceOf(stdClass::class, $args['filter']); @@ -314,6 +322,7 @@ private function executeForCollection(Collection $collection) $args['filter'], array_diff_key($args, ['filter' => 1]) ); + case 'createIndex': assertArrayHasKey('keys', $args); assertInstanceOf(stdClass::class, $args['keys']); @@ -322,6 +331,7 @@ private function executeForCollection(Collection $collection) $args['keys'], array_diff_key($args, ['keys' => 1]) ); + case 'dropIndex': assertArrayHasKey('name', $args); assertIsString($args['name']); @@ -330,6 +340,7 @@ private function executeForCollection(Collection $collection) $args['name'], array_diff_key($args, ['name' => 1]) ); + case 'count': case 'countDocuments': assertArrayHasKey('filter', $args); @@ -339,8 +350,10 @@ private function executeForCollection(Collection $collection) $args['filter'], array_diff_key($args, ['filter' => 1]) ); + case 'estimatedDocumentCount': return $collection->estimatedDocumentCount($args); + case 'deleteMany': case 'deleteOne': case 'findOneAndDelete': @@ -351,6 +364,7 @@ private function executeForCollection(Collection $collection) $args['filter'], array_diff_key($args, ['filter' => 1]) ); + case 'distinct': if (isset($args['session']) && $args['session']->isInTransaction()) { // Transaction, but sharded cluster? @@ -367,8 +381,10 @@ private function executeForCollection(Collection $collection) $args['filter'], array_diff_key($args, ['fieldName' => 1, 'filter' => 1]) ); + case 'drop': return $collection->drop($args); + case 'find': assertArrayHasKey('filter', $args); assertInstanceOf(stdClass::class, $args['filter']); @@ -377,6 +393,7 @@ private function executeForCollection(Collection $collection) $args['filter'], array_diff_key($args, ['filter' => 1]) )); + case 'findOne': assertArrayHasKey('filter', $args); assertInstanceOf(stdClass::class, $args['filter']); @@ -385,6 +402,7 @@ private function executeForCollection(Collection $collection) $args['filter'], array_diff_key($args, ['filter' => 1]) ); + case 'findOneAndReplace': if (isset($args['returnDocument'])) { $args['returnDocument'] = strtolower($args['returnDocument']); @@ -395,7 +413,6 @@ private function executeForCollection(Collection $collection) : FindOneAndReplace::RETURN_DOCUMENT_BEFORE; } // Fall through - case 'replaceOne': assertArrayHasKey('filter', $args); assertArrayHasKey('replacement', $args); @@ -407,6 +424,7 @@ private function executeForCollection(Collection $collection) $args['replacement'], array_diff_key($args, ['filter' => 1, 'replacement' => 1]) ); + case 'findOneAndUpdate': if (isset($args['returnDocument'])) { $args['returnDocument'] = strtolower($args['returnDocument']); @@ -417,7 +435,6 @@ private function executeForCollection(Collection $collection) : FindOneAndUpdate::RETURN_DOCUMENT_BEFORE; } // Fall through - case 'updateMany': case 'updateOne': assertArrayHasKey('filter', $args); @@ -430,6 +447,7 @@ private function executeForCollection(Collection $collection) $args['update'], array_diff_key($args, ['filter' => 1, 'update' => 1]) ); + case 'insertMany': // Merge nested and top-level options (see: SPEC-1158) $options = isset($args['options']) ? (array) $args['options'] : []; @@ -442,6 +460,7 @@ private function executeForCollection(Collection $collection) $args['documents'], $options ); + case 'insertOne': assertArrayHasKey('document', $args); assertInstanceOf(stdClass::class, $args['document']); @@ -450,8 +469,10 @@ private function executeForCollection(Collection $collection) $args['document'], array_diff_key($args, ['document' => 1]) ); + case 'listIndexes': return iterator_to_array($collection->listIndexes($args)); + case 'mapReduce': assertArrayHasKey('map', $args); assertArrayHasKey('reduce', $args); @@ -466,6 +487,7 @@ private function executeForCollection(Collection $collection) $args['out'], array_diff_key($args, ['map' => 1, 'reduce' => 1, 'out' => 1]) ); + default: Assert::fail('Unsupported collection operation: ' . $this->name); } @@ -512,6 +534,7 @@ private function executeForCursor(Cursor $cursor) } while (! $cursor->valid()); return $cursor->current(); + default: Assert::fail('Unsupported cursor operation: ' . $this->name); } @@ -530,6 +553,7 @@ private function executeForDatabase(Database $database) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) )); + case 'createChangeStream': assertArrayHasKey('pipeline', $args); assertIsArray($args['pipeline']); @@ -538,6 +562,7 @@ private function executeForDatabase(Database $database) $args['pipeline'], array_diff_key($args, ['pipeline' => 1]) ); + case 'createCollection': assertArrayHasKey('collection', $args); assertIsString($args['collection']); @@ -546,6 +571,7 @@ private function executeForDatabase(Database $database) $args['collection'], array_diff_key($args, ['collection' => 1]) ); + case 'dropCollection': assertArrayHasKey('collection', $args); assertIsString($args['collection']); @@ -554,10 +580,13 @@ private function executeForDatabase(Database $database) $args['collection'], array_diff_key($args, ['collection' => 1]) ); + case 'listCollectionNames': return iterator_to_array($database->listCollectionNames($args)); + case 'listCollections': return iterator_to_array($database->listCollections($args)); + case 'runCommand': assertArrayHasKey('command', $args); assertInstanceOf(stdClass::class, $args['command']); @@ -566,6 +595,7 @@ private function executeForDatabase(Database $database) $args['command'], array_diff_key($args, ['command' => 1]) )->toArray()[0]; + default: Assert::fail('Unsupported database operation: ' . $this->name); } @@ -578,12 +608,16 @@ private function executeForSession(Session $session) switch ($this->name) { case 'abortTransaction': return $session->abortTransaction(); + case 'commitTransaction': return $session->commitTransaction(); + case 'endSession': return $session->endSession(); + case 'startTransaction': return $session->startTransaction($args); + case 'withTransaction': assertArrayHasKey('callback', $args); assertIsArray($args['callback']); @@ -594,13 +628,14 @@ private function executeForSession(Session $session) return new Operation($o, $this->context); }, $args['callback']); - $callback = function () use ($operations) { + $callback = function () use ($operations): void { foreach ($operations as $operation) { $operation->assert(true); // rethrow exceptions } }; return with_transaction($session, $callback, array_diff_key($args, ['callback' => 1])); + default: Assert::fail('Unsupported session operation: ' . $this->name); } @@ -615,6 +650,7 @@ private function executeForBucket(Bucket $bucket) assertArrayHasKey('id', $args); return $bucket->delete($args['id']); + case 'downloadByName': assertArrayHasKey('filename', $args); assertIsString($args['filename']); @@ -623,10 +659,12 @@ private function executeForBucket(Bucket $bucket) $args['filename'], array_diff_key($args, ['filename' => 1]) )); + case 'download': assertArrayHasKey('id', $args); return stream_get_contents($bucket->openDownloadStream($args['id'])); + case 'uploadWithId': assertArrayHasKey('id', $args); $args['_id'] = $args['id']; @@ -642,6 +680,7 @@ private function executeForBucket(Bucket $bucket) $args['source'], array_diff_key($args, ['filename' => 1, 'source' => 1]) ); + default: Assert::fail('Unsupported bucket operation: ' . $this->name); } @@ -762,12 +801,13 @@ private function executeForTestRunner() }, $args['operations']); return (new Loop($operations, $this->context, array_diff_key($args, ['operations' => 1])))->execute(); + default: Assert::fail('Unsupported test runner operation: ' . $this->name); } } - private function getIndexNames(string $databaseName, string $collectionName) : array + private function getIndexNames(string $databaseName, string $collectionName): array { return array_map( function (IndexInfo $indexInfo) { @@ -777,7 +817,7 @@ function (IndexInfo $indexInfo) { ); } - private function prepareArguments() : array + private function prepareArguments(): array { $args = $this->arguments; @@ -795,7 +835,7 @@ private function prepareArguments() : array return Util::prepareCommonOptions($args); } - private static function prepareBulkWriteRequest(stdClass $request) : array + private static function prepareBulkWriteRequest(stdClass $request): array { $request = (array) $request; assertCount(1, $request); @@ -817,10 +857,12 @@ private static function prepareBulkWriteRequest(stdClass $request) : array array_diff_key($args, ['filter' => 1]), ], ]; + case 'insertOne': assertArrayHasKey('document', $args); - return [ 'insertOne' => [ $args['document']]]; + return ['insertOne' => [$args['document']]]; + case 'replaceOne': assertArrayHasKey('filter', $args); assertArrayHasKey('replacement', $args); @@ -834,6 +876,7 @@ private static function prepareBulkWriteRequest(stdClass $request) : array array_diff_key($args, ['filter' => 1, 'replacement' => 1]), ], ]; + case 'updateMany': case 'updateOne': assertArrayHasKey('filter', $args); @@ -848,12 +891,13 @@ private static function prepareBulkWriteRequest(stdClass $request) : array array_diff_key($args, ['filter' => 1, 'update' => 1]), ], ]; + default: Assert::fail('Unsupported bulk write request: ' . $type); } } - private static function prepareUploadArguments(array $args) : array + private static function prepareUploadArguments(array $args): array { $source = $args['source'] ?? null; assertIsObject($source); diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index 4fd46f6e3..e0141a489 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -4,6 +4,7 @@ use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use stdClass; + use function array_diff; use function in_array; use function PHPUnit\Framework\assertContains; @@ -17,17 +18,17 @@ class RunOnRequirement { - const TOPOLOGY_SINGLE = 'single'; - const TOPOLOGY_REPLICASET = 'replicaset'; - const TOPOLOGY_SHARDED = 'sharded'; - const TOPOLOGY_SHARDED_REPLICASET = 'sharded-replicaset'; - const TOPOLOGY_LOAD_BALANCED = 'load-balanced'; + public const TOPOLOGY_SINGLE = 'single'; + public const TOPOLOGY_REPLICASET = 'replicaset'; + public const TOPOLOGY_SHARDED = 'sharded'; + public const TOPOLOGY_SHARDED_REPLICASET = 'sharded-replicaset'; + public const TOPOLOGY_LOAD_BALANCED = 'load-balanced'; - const SERVERLESS_REQUIRE = 'require'; - const SERVERLESS_FORBID = 'forbid'; - const SERVERLESS_ALLOW = 'allow'; + public const SERVERLESS_REQUIRE = 'require'; + public const SERVERLESS_FORBID = 'forbid'; + public const SERVERLESS_ALLOW = 'allow'; - const VERSION_PATTERN = '/^[0-9]+(\\.[0-9]+){1,2}$/'; + public const VERSION_PATTERN = '/^[0-9]+(\\.[0-9]+){1,2}$/'; /** @var string */ private $minServerVersion; @@ -103,7 +104,7 @@ public function __construct(stdClass $o) } } - public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated, bool $isServerless) : bool + public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated, bool $isServerless): bool { if (isset($this->minServerVersion) && version_compare($serverVersion, $this->minServerVersion, '<')) { return false; @@ -141,7 +142,7 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s return true; } - private function isTopologySatisfied(string $topology) : bool + private function isTopologySatisfied(string $topology): bool { if (in_array($topology, $this->topologies)) { return true; diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index b18684f1b..ec112a730 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -7,6 +7,7 @@ use MongoDB\Tests\FunctionalTestCase; use PHPUnit\Framework\SkippedTest; use PHPUnit\Framework\Warning; + use function basename; use function dirname; use function glob; @@ -52,7 +53,7 @@ class UnifiedSpecTest extends FunctionalTestCase /** @var UnifiedTestRunner */ private static $runner; - public static function setUpBeforeClass() : void + public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); @@ -61,7 +62,7 @@ public static function setUpBeforeClass() : void self::$runner = new UnifiedTestRunner(static::getUri(true)); } - public function setUp() : void + public function setUp(): void { parent::setUp(); @@ -73,7 +74,7 @@ public function setUp() : void /** * @dataProvider provideChangeStreamsTests */ - public function testChangeStreams(UnifiedTestCase $test) + public function testChangeStreams(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -86,7 +87,7 @@ public function provideChangeStreamsTests() /** * @dataProvider provideCollectionManagementTests */ - public function testCollectionManagement(UnifiedTestCase $test) + public function testCollectionManagement(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -99,7 +100,7 @@ public function provideCollectionManagementTests() /** * @dataProvider provideCrudTests */ - public function testCrud(UnifiedTestCase $test) + public function testCrud(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -112,7 +113,7 @@ public function provideCrudTests() /** * @dataProvider provideGridFSTests */ - public function testGridFS(UnifiedTestCase $test) + public function testGridFS(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -125,7 +126,7 @@ public function provideGridFSTests() /** * @dataProvider provideTransactionsTests */ - public function testTransactions(UnifiedTestCase $test) + public function testTransactions(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -139,7 +140,7 @@ public function provideTransactionsTests() * @dataProvider provideVersionedApiTests * @group versioned-api */ - public function testVersionedApi(UnifiedTestCase $test) + public function testVersionedApi(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -152,7 +153,7 @@ public function provideVersionedApiTests() /** * @dataProvider providePassingTests */ - public function testPassingTests(UnifiedTestCase $test) + public function testPassingTests(UnifiedTestCase $test): void { self::$runner->run($test); } @@ -165,7 +166,7 @@ public function providePassingTests() /** * @dataProvider provideFailingTests */ - public function testFailingTests(UnifiedTestCase $test) + public function testFailingTests(UnifiedTestCase $test): void { // Cannot use expectException(), as it ignores PHPUnit Exceptions $failed = false; @@ -186,6 +187,7 @@ public function testFailingTests(UnifiedTestCase $test) */ $failed = ! ($e instanceof SkippedTest || $e instanceof Warning); } + // phpcs:enable $this->assertTrue($failed, 'Expected test to throw an exception'); @@ -196,7 +198,7 @@ public function provideFailingTests() yield from $this->provideTests(__DIR__ . '/valid-fail/*.json'); } - private function provideTests(string $pattern) : Generator + private function provideTests(string $pattern): Generator { foreach (glob($pattern) as $filename) { $group = basename(dirname($filename)); diff --git a/tests/UnifiedSpecTests/UnifiedTestCase.php b/tests/UnifiedSpecTests/UnifiedTestCase.php index 725194e38..d3007f0cf 100644 --- a/tests/UnifiedSpecTests/UnifiedTestCase.php +++ b/tests/UnifiedSpecTests/UnifiedTestCase.php @@ -5,6 +5,7 @@ use Generator; use IteratorAggregate; use stdClass; + use function file_get_contents; use function MongoDB\BSON\fromJSON; use function MongoDB\BSON\toPHP; @@ -38,7 +39,7 @@ final class UnifiedTestCase implements IteratorAggregate /** @var array|null */ private $initialData; - private function __construct(stdClass $test, string $schemaVersion, array $runOnRequirements = null, array $createEntities = null, array $initialData = null) + private function __construct(stdClass $test, string $schemaVersion, ?array $runOnRequirements = null, ?array $createEntities = null, ?array $initialData = null) { $this->test = $test; $this->schemaVersion = $schemaVersion; @@ -68,7 +69,7 @@ public function getIterator() /** * Yields UnifiedTestCase objects for a JSON file. */ - public static function fromFile(string $filename) : Generator + public static function fromFile(string $filename): Generator { /* Decode the file through the driver's extended JSON parser to ensure * proper handling of special types. */ @@ -83,7 +84,7 @@ public static function fromFile(string $filename) : Generator * The top-level and test-level "description" fields will be concatenated * and used as the key for each yielded value. */ - public static function fromJSON(stdClass $json) : Generator + public static function fromJSON(stdClass $json): Generator { $description = $json->description; $schemaVersion = $json->schemaVersion; diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index d30a7d6ec..03d607419 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -16,6 +16,7 @@ use stdClass; use Throwable; use UnexpectedValueException; + use function call_user_func; use function count; use function gc_collect_cycles; @@ -39,13 +40,13 @@ */ final class UnifiedTestRunner { - const ATLAS_TLD = 'mongodb.net'; + public const ATLAS_TLD = 'mongodb.net'; - const SERVER_ERROR_INTERRUPTED = 11601; - const SERVER_ERROR_UNAUTHORIZED = 13; + public const SERVER_ERROR_INTERRUPTED = 11601; + public const SERVER_ERROR_UNAUTHORIZED = 13; - const MIN_SCHEMA_VERSION = '1.0'; - const MAX_SCHEMA_VERSION = '1.4'; + public const MIN_SCHEMA_VERSION = '1.0'; + public const MAX_SCHEMA_VERSION = '1.4'; /** @var MongoDB\Client */ private $internalClient; @@ -78,7 +79,7 @@ public function __construct(string $internalClientUri) } } - public function run(UnifiedTestCase $test) + public function run(UnifiedTestCase $test): void { $this->doSetUp(); $hasFailed = false; @@ -115,12 +116,12 @@ public function run(UnifiedTestCase $test) * * @param callable(EntityMap):void $entityMapObserver */ - public function setEntityMapObserver(callable $entityMapObserver) + public function setEntityMapObserver(callable $entityMapObserver): void { $this->entityMapObserver = $entityMapObserver; } - private function doSetUp() + private function doSetUp(): void { /* The transactions spec advises calling killAllSessions only at the * start of the test suite and after failed tests; however, the "unpin @@ -132,7 +133,7 @@ private function doSetUp() $this->failPointObserver->start(); } - private function doTearDown(bool $hasFailed) + private function doTearDown(bool $hasFailed): void { $this->entityMap = null; @@ -149,7 +150,7 @@ private function doTearDown(bool $hasFailed) gc_collect_cycles(); } - private function doTestCase(stdClass $test, string $schemaVersion, array $runOnRequirements = null, array $createEntities = null, array $initialData = null) + private function doTestCase(stdClass $test, string $schemaVersion, ?array $runOnRequirements = null, ?array $createEntities = null, ?array $initialData = null): void { if (! $this->isSchemaVersionSupported($schemaVersion)) { Assert::markTestIncomplete(sprintf('Test format schema version "%s" is not supported', $schemaVersion)); @@ -219,7 +220,7 @@ private function doTestCase(stdClass $test, string $schemaVersion, array $runOnR * * @throws SkippedTest unless one or more runOnRequirements are met */ - private function checkRunOnRequirements(array $runOnRequirements) + private function checkRunOnRequirements(array $runOnRequirements): void { static $cachedIsSatisfiedArgs; @@ -252,14 +253,14 @@ private function checkRunOnRequirements(array $runOnRequirements) )); } - private function getPrimaryServer() : Server + private function getPrimaryServer(): Server { $manager = $this->internalClient->getManager(); return $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY)); } - private function getServerParameters() : stdClass + private function getServerParameters(): stdClass { $database = $this->internalClient->selectDatabase('admin'); $cursor = $database->command( @@ -277,7 +278,7 @@ private function getServerParameters() : stdClass return $cursor->toArray()[0]; } - private function getServerVersion() : string + private function getServerVersion(): string { $database = $this->internalClient->selectDatabase('admin'); $buildInfo = $database->command(['buildInfo' => 1])->toArray()[0]; @@ -294,18 +295,21 @@ private function getServerVersion() : string * * @throws UnexpectedValueException if topology is neither single nor RS nor sharded */ - private function getTopology() : string + private function getTopology(): string { // TODO: detect load-balanced topologies once PHPLIB-671 is implemented switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_STANDALONE: return RunOnRequirement::TOPOLOGY_SINGLE; + case Server::TYPE_RS_PRIMARY: return RunOnRequirement::TOPOLOGY_REPLICASET; + case Server::TYPE_MONGOS: return $this->isShardedClusterUsingReplicasets() ? RunOnRequirement::TOPOLOGY_SHARDED_REPLICASET : RunOnRequirement::TOPOLOGY_SHARDED; + default: throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); } @@ -318,7 +322,7 @@ private function getTopology() : string * may be necessary to rewrite this to instead inspect the connection string * or consult an environment variable, as is done in libmongoc. */ - private function isAuthenticated() : bool + private function isAuthenticated(): bool { $database = $this->internalClient->selectDatabase('admin'); $connectionStatus = $database->command(['connectionStatus' => 1])->toArray()[0]; @@ -333,7 +337,7 @@ private function isAuthenticated() : bool /** * Return whether serverless (i.e. proxy as mongos) is being utilized. */ - private function isServerless() : bool + private function isServerless(): bool { // TODO: detect serverless once PHPC-1755 is implemented return false; @@ -342,12 +346,12 @@ private function isServerless() : bool /** * Checks is a test format schema version is supported. */ - private function isSchemaVersionSupported(string $schemaVersion) : bool + private function isSchemaVersionSupported(string $schemaVersion): bool { return version_compare($schemaVersion, self::MIN_SCHEMA_VERSION, '>=') && version_compare($schemaVersion, self::MAX_SCHEMA_VERSION, '<='); } - private function isShardedClusterUsingReplicasets() : bool + private function isShardedClusterUsingReplicasets(): bool { $collection = $this->internalClient->selectCollection('config', 'shards'); $config = $collection->findOne(); @@ -373,7 +377,7 @@ private function isShardedClusterUsingReplicasets() : bool * * This method is a NOP if allowKillAllSessions is false. */ - private function killAllSessions() + private function killAllSessions(): void { static $ignoreErrorCodes = [ self::SERVER_ERROR_INTERRUPTED, // SERVER-38335 @@ -406,7 +410,7 @@ private function killAllSessions() } } - private function assertOutcome(array $outcome) + private function assertOutcome(array $outcome): void { assertNotEmpty($outcome); assertContainsOnly('object', $outcome); @@ -417,7 +421,7 @@ private function assertOutcome(array $outcome) } } - private function prepareInitialData(array $initialData) + private function prepareInitialData(array $initialData): void { assertNotEmpty($initialData); assertContainsOnly('object', $initialData); @@ -433,7 +437,7 @@ private function prepareInitialData(array $initialData) * * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversion */ - private function preventStaleDbVersionError(array $operations, Context $context) + private function preventStaleDbVersionError(array $operations, Context $context): void { if ($this->getPrimaryServer()->getType() !== Server::TYPE_MONGOS) { return; diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 3e57f78ff..2f2c79693 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -6,6 +6,7 @@ use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; use stdClass; + use function array_diff_key; use function array_fill_keys; use function array_key_exists; @@ -25,14 +26,14 @@ final class Util { - public static function assertHasOnlyKeys($arrayOrObject, array $keys) + public static function assertHasOnlyKeys($arrayOrObject, array $keys): void { assertThat($arrayOrObject, logicalOr(isType('array'), isInstanceOf(stdClass::class))); $diff = array_diff_key((array) $arrayOrObject, array_fill_keys($keys, 1)); assertEmpty($diff, 'Unsupported keys: ' . implode(',', array_keys($diff))); } - public static function createReadConcern(stdClass $o) : ReadConcern + public static function createReadConcern(stdClass $o): ReadConcern { self::assertHasOnlyKeys($o, ['level']); @@ -42,7 +43,7 @@ public static function createReadConcern(stdClass $o) : ReadConcern return new ReadConcern($level); } - public static function createReadPreference(stdClass $o) : ReadPreference + public static function createReadPreference(stdClass $o): ReadPreference { self::assertHasOnlyKeys($o, ['mode', 'tagSets', 'maxStalenessSeconds', 'hedge']); @@ -73,7 +74,7 @@ public static function createReadPreference(stdClass $o) : ReadPreference return new ReadPreference($mode, $tagSets, $options); } - public static function createWriteConcern(stdClass $o) : WriteConcern + public static function createWriteConcern(stdClass $o): WriteConcern { self::assertHasOnlyKeys($o, ['w', 'wtimeoutMS', 'journal']); @@ -94,7 +95,7 @@ public static function createWriteConcern(stdClass $o) : WriteConcern return new WriteConcern(...$args); } - public static function prepareCommonOptions(array $options) : array + public static function prepareCommonOptions(array $options): array { if (array_key_exists('readConcern', $options)) { assertIsObject($options['readConcern']); From 1685ebc3187cb723ce63e934ec000e565b77c9c9 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 8 Jul 2021 09:33:12 +0200 Subject: [PATCH 060/321] PHPLIB-675 Add helpers to check collection types to CollectionInfo (#839) * PHPLIB-675 Expose additional methods to access collection info * Use arrayNotHasKey over isset in tests * Add version information to deprecation messages --- src/Model/CollectionInfo.php | 42 +++++++++++++++++++++++++++++- tests/Model/CollectionInfoTest.php | 40 +++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php index afbf63527..63d135de6 100644 --- a/src/Model/CollectionInfo.php +++ b/src/Model/CollectionInfo.php @@ -60,6 +60,8 @@ public function __debugInfo() /** * Return the maximum number of documents to keep in the capped collection. * + * @deprecated 1.0 Deprecated in favor of using getOptions + * * @return integer|null */ public function getCappedMax() @@ -71,6 +73,8 @@ public function getCappedMax() /** * Return the maximum size (in bytes) of the capped collection. * + * @deprecated 1.0 Deprecated in favor of using getOptions + * * @return integer|null */ public function getCappedSize() @@ -79,9 +83,31 @@ public function getCappedSize() return isset($this->info['options']['size']) ? (integer) $this->info['options']['size'] : null; } + /** + * Return information about the _id index for the collection. + * + * @return array + */ + public function getIdIndex(): array + { + return (array) ($this->info['idIndex'] ?? []); + } + + /** + * Return the "info" property of the server response. + * + * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output + * @return array + */ + public function getInfo(): array + { + return (array) ($this->info['info'] ?? []); + } + /** * Return the collection name. * + * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output * @return string */ public function getName() @@ -92,16 +118,30 @@ public function getName() /** * Return the collection options. * + * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output * @return array */ public function getOptions() { - return isset($this->info['options']) ? (array) $this->info['options'] : []; + return (array) ($this->info['options'] ?? []); + } + + /** + * Return the collection type. + * + * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output + * @return string + */ + public function getType(): string + { + return (string) $this->info['type']; } /** * Return whether the collection is a capped collection. * + * @deprecated 1.0 Deprecated in favor of using getOptions + * * @return boolean */ public function isCapped() diff --git a/tests/Model/CollectionInfoTest.php b/tests/Model/CollectionInfoTest.php index 322c39586..ff5a112db 100644 --- a/tests/Model/CollectionInfoTest.php +++ b/tests/Model/CollectionInfoTest.php @@ -8,19 +8,47 @@ class CollectionInfoTest extends TestCase { - public function testGetName(): void + public function testGetBasicInformation(): void { - $info = new CollectionInfo(['name' => 'foo']); + $info = new CollectionInfo([ + 'name' => 'foo', + 'type' => 'view', + 'options' => ['capped' => true, 'size' => 1048576], + 'info' => ['readOnly' => true], + 'idIndex' => ['idIndex' => true], // Dummy option + ]); + $this->assertSame('foo', $info->getName()); + $this->assertSame('foo', $info['name']); + + $this->assertSame('view', $info->getType()); + $this->assertSame('view', $info['type']); + + $this->assertSame(['capped' => true, 'size' => 1048576], $info->getOptions()); + $this->assertSame(['capped' => true, 'size' => 1048576], $info['options']); + + $this->assertSame(['readOnly' => true], $info->getInfo()); + $this->assertSame(['readOnly' => true], $info['info']); + + $this->assertSame(['idIndex' => true], $info->getIdIndex()); + $this->assertSame(['idIndex' => true], $info['idIndex']); } - public function testGetOptions(): void + public function testMissingFields(): void { - $info = new CollectionInfo(['name' => 'foo']); + $info = new CollectionInfo([ + 'name' => 'foo', + 'type' => 'view', + ]); + $this->assertSame([], $info->getOptions()); + $this->assertArrayNotHasKey('options', $info); - $info = new CollectionInfo(['name' => 'foo', 'options' => ['capped' => true, 'size' => 1048576]]); - $this->assertSame(['capped' => true, 'size' => 1048576], $info->getOptions()); + $this->assertSame([], $info->getInfo()); + $this->assertArrayNotHasKey('info', $info); + + $this->assertSame([], $info->getIdIndex()); + $this->assertArrayNotHasKey('idIndex', $info); } public function testCappedCollectionMethods(): void From e98f22a5ad51568e177485e1278150189acde77e Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 13 Jul 2021 17:33:29 +0200 Subject: [PATCH 061/321] PHPLIB-675 Document new CollectionInfo methods (#841) * Document deprecation of capped collection helpers * Add detail about where collection information comes from * Document new CollectionInfo helpers * Address review feedback * Fix wrong backticks --- docs/reference/enumeration-classes.txt | 3 + ...ongoDBModelCollectionInfo-getCappedMax.txt | 6 ++ ...ngoDBModelCollectionInfo-getCappedSize.txt | 6 ++ .../MongoDBModelCollectionInfo-getIdIndex.txt | 73 +++++++++++++++++++ .../MongoDBModelCollectionInfo-getInfo.txt | 59 +++++++++++++++ .../MongoDBModelCollectionInfo-getName.txt | 3 +- .../MongoDBModelCollectionInfo-getOptions.txt | 3 +- .../MongoDBModelCollectionInfo-getType.txt | 52 +++++++++++++ .../MongoDBModelCollectionInfo-isCapped.txt | 6 ++ 9 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt create mode 100644 docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt create mode 100644 docs/reference/method/MongoDBModelCollectionInfo-getType.txt diff --git a/docs/reference/enumeration-classes.txt b/docs/reference/enumeration-classes.txt index 7eac097e3..bb2a629a8 100644 --- a/docs/reference/enumeration-classes.txt +++ b/docs/reference/enumeration-classes.txt @@ -43,8 +43,11 @@ Methods /reference/method/MongoDBModelCollectionInfo-getCappedMax /reference/method/MongoDBModelCollectionInfo-getCappedSize + /reference/method/MongoDBModelCollectionInfo-getIdIndex + /reference/method/MongoDBModelCollectionInfo-getInfo /reference/method/MongoDBModelCollectionInfo-getName /reference/method/MongoDBModelCollectionInfo-getOptions + /reference/method/MongoDBModelCollectionInfo-getType /reference/method/MongoDBModelCollectionInfo-isCapped ---- diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt b/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt index fb86ee19a..99a7d082e 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt @@ -2,6 +2,8 @@ MongoDB\\Model\\CollectionInfo::getCappedMax() ============================================== +.. deprecated:: 1.9 + .. default-domain:: mongodb .. contents:: On this page @@ -28,6 +30,10 @@ Return Values The document limit for the capped collection. If the collection is not capped, ``null`` will be returned. +This method is deprecated in favor of using +:phpmethod:`MongoDB\\Model\\CollectionInfo::getOptions()` and accessing the +``max`` key. + Examples -------- diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt b/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt index a3b1ce48f..1d94a4042 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt @@ -2,6 +2,8 @@ MongoDB\\Model\\CollectionInfo::getCappedSize() =============================================== +.. deprecated:: 1.9 + .. default-domain:: mongodb .. contents:: On this page @@ -29,6 +31,10 @@ Return Values The size limit for the capped collection in bytes. If the collection is not capped, ``null`` will be returned. +This method is deprecated in favor of using +:phpmethod:`MongoDB\\Model\\CollectionInfo::getOptions()` and accessing the +``size`` key. + Examples -------- diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt b/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt new file mode 100644 index 000000000..4c0e4aa31 --- /dev/null +++ b/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt @@ -0,0 +1,73 @@ +============================================ +MongoDB\\Model\\CollectionInfo::getIdIndex() +============================================ + +.. versionadded:: 1.9 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getIdIndex() + + Returns information about the ``_id`` field index. + + .. code-block:: php + + function getIdIndex(): array + +Return Values +------------- + +An array containing information on the ``_id`` index. This corresponds to the +``idIndex`` field returned in the ``listCollections`` command reply. + +Examples +-------- + +.. code-block:: php + + 'view', + 'name' => 'foo', + 'idIndex' => [ + 'v' => 2, + 'key' => ['_id' => 1], + 'name' => '_id', + 'ns' => 'test.foo', + ], + ]); + + var_dump($info->getIdIndex()); + +The output would then resemble:: + + array(4) { + ["v"]=> + int(2) + ["key"]=> + array(1) { + ["_id"]=> + int(1) + } + ["name"]=> + string(3) "_id" + ["ns"]=> + string(8) "test.foo" + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::createCollection()` +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt b/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt new file mode 100644 index 000000000..40068e3b4 --- /dev/null +++ b/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt @@ -0,0 +1,59 @@ +========================================= +MongoDB\\Model\\CollectionInfo::getInfo() +========================================= + +.. versionadded:: 1.9 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getInfo() + + Returns additional information about the collection. + + .. code-block:: php + + function getInfo(): array + +Return Values +------------- + +An array containing extra information about the collection. This corresponds to +the ``info`` field returned in the ``listCollections`` command reply. + +Examples +-------- + +.. code-block:: php + + 'view', + 'name' => 'foo', + 'info' => ['readOnly' => true] + ]); + + var_dump($info->getInfo()); + +The output would then resemble:: + + array(1) { + ["readOnly"]=> + bool(true) + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::createCollection()` +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getName.txt b/docs/reference/method/MongoDBModelCollectionInfo-getName.txt index 42226c203..76af1fa9b 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getName.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getName.txt @@ -24,7 +24,8 @@ Definition Return Values ------------- -The collection name. +The collection name. This corresponds to the ``name`` field returned in the +``listCollections`` command reply. Examples -------- diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt b/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt index 845068163..4c7fabe55 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt @@ -26,7 +26,8 @@ Definition Return Values ------------- -The collection options. +The collection options. This corresponds to the ``options`` field returned in +the ``listCollections`` command reply. Examples -------- diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getType.txt b/docs/reference/method/MongoDBModelCollectionInfo-getType.txt new file mode 100644 index 000000000..b900efed3 --- /dev/null +++ b/docs/reference/method/MongoDBModelCollectionInfo-getType.txt @@ -0,0 +1,52 @@ +========================================= +MongoDB\\Model\\CollectionInfo::getType() +========================================= + +.. versionadded:: 1.9 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Model\\CollectionInfo::getType() + + Return the collection type. + + .. code-block:: php + + function getType(): string + +Return Values +------------- + +The collection type. This corresponds to the ``type`` field returned in the +``listCollections`` command reply. + +Examples +-------- + +.. code-block:: php + + 'collection', 'name' => 'foo']); + + echo $info->getType(); + +The output would then resemble:: + + collection + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::createCollection()` +- :manual:`listCollections ` command + reference in the MongoDB manual diff --git a/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt b/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt index a583a83fc..15957ae80 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt @@ -2,6 +2,8 @@ MongoDB\\Model\\CollectionInfo::isCapped() ========================================== +.. deprecated:: 1.9 + .. default-domain:: mongodb .. contents:: On this page @@ -27,6 +29,10 @@ Return Values A boolean indicating whether the collection is a capped collection. +This method is deprecated in favor of using +:phpmethod:`MongoDB\\Model\\CollectionInfo::getOptions()` and accessing the +``capped`` key. + Examples -------- From a5e78be52f953d14e4d6bceb9922941dfbd50400 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 13 Jul 2021 14:36:16 -0400 Subject: [PATCH 062/321] Revise release notes template --- CONTRIBUTING.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6734d47b..cdf77489c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,7 +147,7 @@ The following template should be used for creating GitHub release notes via [this form](https://github.com/mongodb/mongo-php-library/releases/new). ``` -The PHP team is happy to announce that version X.Y.Z of the MongoDB PHP library is now available. This library is a high-level abstraction for the [`mongodb`](http://php.net/mongodb) extension. +The PHP team is happy to announce that version X.Y.Z of the MongoDB PHP library is now available. **Release Highlights** @@ -161,11 +161,6 @@ $JIRA_URL Documentation for this library may be found at: https://docs.mongodb.com/php-library/ -**Feedback** - -If you encounter any bugs or issues with this library, please report them via this form: -https://jira.mongodb.org/secure/CreateIssue.jspa?pid=12483&issuetype=1 - **Installation** This library may be installed or upgraded with: From 9e6e0ccd647936c959582ada9570acde6913470c Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 13 Jul 2021 21:08:13 +0200 Subject: [PATCH 063/321] PHPLIB-690 Update documentation for time series collection options (#843) * PHPLIB-690 Update documentation for time series collection options * Apply suggestions from code review Co-authored-by: Jeremy Mikola Co-authored-by: Jeremy Mikola --- ...s-MongoDBDatabase-method-createCollection-option.yaml | 9 ++++++--- .../method/MongoDBDatabase-createCollection.txt | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 7695309b3..f0f321172 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -38,8 +38,9 @@ arg_name: option name: expireAfterSeconds type: integer description: | - Allows specifying a TTL after which documents will be removed from a - time-series collection. + Used to automatically delete documents in time series collections. See the + :manual:`create ` command documentation for more + information. This option is available in MongoDB 5.0+ and will result in an exception at execution time if specified for an older server version. @@ -152,7 +153,9 @@ arg_name: option name: timeseries type: array|object description: | - Allows users to specify options for time-series collections. + An object containing options for creating time series collections. See the + :manual:`create ` command documentation for + supported options. This option is available in MongoDB 5.0+ and will result in an exception at execution time if specified for an older server version. diff --git a/docs/reference/method/MongoDBDatabase-createCollection.txt b/docs/reference/method/MongoDBDatabase-createCollection.txt index 8db6696c4..f024806d7 100644 --- a/docs/reference/method/MongoDBDatabase-createCollection.txt +++ b/docs/reference/method/MongoDBDatabase-createCollection.txt @@ -97,3 +97,4 @@ See Also - :manual:`create ` command reference in the MongoDB manual - :manual:`db.createCollection() ` +- :manual:`Time Series Collections ` From 4afe9254e87252879bfbb625858e78fbe072daa0 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 13 Jul 2021 22:03:24 +0200 Subject: [PATCH 064/321] Update tested ext-mongodb versions (#842) --- .evergreen/config.yml | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 7cfd008f0..37ff9b8b6 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -468,27 +468,23 @@ axes: - id: driver-versions display_name: Driver Version values: - # TODO: this axis can be cleaned up as we move towards a 1.10 release: # * lowest-supported can be enabled once a 1.10 patch release has been tagged - # * latest-stable can be updated when we start tagging 1.10 releases (even beta) - # * 1.10-dev can be enabled once 1.10 has been branched - # * latest-dev can be enabled once 1.10 has been branched # - id: "lowest-supported" -# display_name: "1.10.0-alpha1" +# display_name: "1.10.0" # variables: -# EXTENSION_VERSION: "1.10.0alpha1" - - id: "latest" - display_name: "1.10-dev (master)" +# EXTENSION_VERSION: "1.10.0" + - id: "latest-stable" + display_name: "Latest Stable (1.10.x)" + variables: + EXTENSION_VERSION: "stable" + - id: "upcoming-stable" + display_name: "1.10-dev" + variables: + EXTENSION_BRANCH: "v1.10" + - id: "latest-dev" + display_name: "1.11-dev (master)" variables: EXTENSION_BRANCH: "master" -# - id: "1.10-dev" -# display_name: "1.10-dev" -# variables: -# EXTENSION_BRANCH: "v1.10" -# - id: "latest-dev" -# display_name: "1.11-dev (master)" -# variables: -# EXTENSION_BRANCH: "master" - id: os-php7 display_name: OS @@ -578,7 +574,7 @@ buildvariants: # Tests all PHP versions on all operating systems. # Only tests against latest MongoDB and ext-mongodb versions - matrix_name: "test-php-versions" - matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest" } + matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest-stable" } exclude_spec: # rhel71-power8 fails due to not reaching pecl - { "os-php7": "rhel71-power8", "php-versions": "*", edge-versions: "*", "driver-versions": "*" } @@ -604,7 +600,7 @@ buildvariants: # Only tests on Ubuntu 18.04, with latest stable PHP and driver versions # Tests against various topologies - matrix_name: "test-mongodb-versions" - matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest" } + matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest-stable" } display_name: "MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" @@ -615,7 +611,7 @@ buildvariants: # Enables --prefer-lowest for composer to test oldest dependencies against all server versions # TODO: driver-versions can be changed back to lowest-supported when that version is enabled in the axis - matrix_name: "test-dependencies" - matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "latest" } + matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "latest-stable" } display_name: "Dependencies: ${dependencies}, MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" @@ -623,14 +619,14 @@ buildvariants: - name: "test-sharded_cluster" - matrix_name: "atlas-data-lake-test" - matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest" } + matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Atlas Data Lake test" run_on: rhel70 tasks: - name: "test-atlas-data-lake" - matrix_name: "test-versioned-api" - matrix_spec: { "php-edge-versions": "latest-stable", "versions": ["5.0", "latest"], "driver-versions": "latest" } + matrix_spec: { "php-edge-versions": "latest-stable", "versions": ["5.0", "latest"], "driver-versions": "latest-stable" } display_name: "Versioned API - ${versions}" run_on: rhel70 tasks: From ce591998fccd7a1b64d4354542f33b14beb0c089 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Jul 2021 11:21:23 -0400 Subject: [PATCH 065/321] Fix RST syntax for listCollections link --- docs/reference/method/MongoDBDatabase-listCollections.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/method/MongoDBDatabase-listCollections.txt b/docs/reference/method/MongoDBDatabase-listCollections.txt index 99fd69f51..0ca7b2263 100644 --- a/docs/reference/method/MongoDBDatabase-listCollections.txt +++ b/docs/reference/method/MongoDBDatabase-listCollections.txt @@ -114,7 +114,7 @@ The output would then resemble:: See Also -------- -- :manual:`listCollections ` command reference in the MongoDB manual - `Enumerating Collections `_ From c4932f913e0c32b1502f8782a3844357317e6bb6 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Jul 2021 11:24:15 -0400 Subject: [PATCH 066/321] Use "array|object" instead of "document" in MapReduce docs --- .../apiargs-MongoDBCollection-method-mapReduce-option.yaml | 4 ++-- .../apiargs-MongoDBCollection-method-mapReduce-param.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml index a2e97d11c..008fb0fbd 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml @@ -40,7 +40,7 @@ source: --- arg_name: option name: query -type: document +type: array|object description: | Specifies the selection criteria using query operators for determining the documents input to the map function. @@ -58,7 +58,7 @@ source: --- arg_name: option name: scope -type: document +type: array|object description: | Specifies global variables that are accessible in the map, reduce, and finalize functions. diff --git a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml index 401d49edc..b6b92531f 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-param.yaml @@ -20,7 +20,7 @@ optional: false --- arg_name: param name: $out -type: string|document +type: string|array|object description: | Specifies where to output the result of the map-reduce operation. You can either output to a collection or return the result inline. On a primary member From d28dece803b42f8994fcce6fc093a49565c2a545 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Jul 2021 11:26:58 -0400 Subject: [PATCH 067/321] PHPLIB-309 and PHPLIB-315: Fix docs for jsMode and verbose MapReduce opts PHPLIB no longer specifies a default value for either of these options. --- .../apiargs-MongoDBCollection-method-mapReduce-option.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml index a93239c81..0579b7946 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml @@ -22,7 +22,7 @@ name: jsMode type: boolean description: | Specifies whether to convert intermediate data into BSON format between the - execution of the map and reduce functions. The default is ``false``. + execution of the map and reduce functions. interface: phpmethod operation: ~ optional: true @@ -89,7 +89,6 @@ name: verbose type: boolean description: | Specifies whether to include the timing information in the result information. - The default is ``true``. interface: phpmethod operation: ~ optional: true From 1c930decedfee37e5b231c3cb9e866201c42e5d2 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Jul 2021 11:30:57 -0400 Subject: [PATCH 068/321] Fix RST syntax for listCollections link --- docs/reference/method/MongoDBDatabase-listCollectionNames.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/method/MongoDBDatabase-listCollectionNames.txt b/docs/reference/method/MongoDBDatabase-listCollectionNames.txt index 6e973df19..86872bbbc 100644 --- a/docs/reference/method/MongoDBDatabase-listCollectionNames.txt +++ b/docs/reference/method/MongoDBDatabase-listCollectionNames.txt @@ -91,7 +91,7 @@ See Also -------- - :phpmethod:`MongoDB\\Database::listCollections()` -- :manual:`listCollections ` command reference in the MongoDB manual - `Enumerating Collections `_ From a4b172c779c889ecddfbc8c737aefad100c45a49 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Jul 2021 11:36:52 -0400 Subject: [PATCH 069/321] PHPLIB-663: Document aggregate "let" option (#846) --- ...-MongoDBCollection-method-aggregate-option.yaml | 6 ++++++ ...gs-MongoDBDatabase-method-aggregate-option.yaml | 6 ++++++ docs/includes/apiargs-aggregate-option.yaml | 14 ++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml index 86edc1d50..6d1f0c434 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml @@ -28,6 +28,12 @@ source: post: | .. versionadded:: 1.3 --- +source: + file: apiargs-aggregate-option.yaml + ref: let +post: | + .. versionadded:: 1.9 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml index 5d80f32aa..b94d80d48 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml @@ -22,6 +22,12 @@ source: file: apiargs-common-option.yaml ref: hint --- +source: + file: apiargs-aggregate-option.yaml + ref: let +post: | + .. versionadded:: 1.9 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-aggregate-option.yaml b/docs/includes/apiargs-aggregate-option.yaml index 3de7a09db..7e61ff82c 100644 --- a/docs/includes/apiargs-aggregate-option.yaml +++ b/docs/includes/apiargs-aggregate-option.yaml @@ -49,4 +49,18 @@ description: | interface: phpmethod operation: ~ optional: true +--- +arg_name: option +name: let +type: array|object +description: | + Map of parameter names and values. Values must be constant or closed + expressions that do not reference document fields. Parameters can then be + accessed as variables in an aggregate expression context (e.g. ``$$var``). + + This is not supported for server versions prior to 5.0 and will result in an + exception at execution time if used. +interface: phpmethod +operation: ~ +optional: true ... From 105e728d9030afe9f963c3dc7b7c561ef74db2f0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 26 Jul 2021 13:57:17 -0400 Subject: [PATCH 070/321] Add missing use statement for assertIsBool This was missed in 2fc7e896847bfd952899f10d98e62fd83037954d --- tests/UnifiedSpecTests/RunOnRequirement.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index e0141a489..17eb7826e 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -11,6 +11,7 @@ use function PHPUnit\Framework\assertContainsOnly; use function PHPUnit\Framework\assertEmpty; use function PHPUnit\Framework\assertIsArray; +use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertMatchesRegularExpression; From 722679fb633a405f2f127f0498627e755b57b757 Mon Sep 17 00:00:00 2001 From: Tanli Su <46271307+tanlisu@users.noreply.github.com> Date: Mon, 26 Jul 2021 15:12:01 -0400 Subject: [PATCH 071/321] PHPLIB-518: RenameCollection operation (#840) * PHPLIB-518: RenameCollection operation * Adds Database::renameCollection() and Collection::rename() methods. * Move assertCollectionDoesNotExist() and assertCollectionExists() to FunctionalTestCase --- ...ongoDBCollection-method-rename-option.yaml | 27 +++ ...MongoDBCollection-method-rename-param.yaml | 25 +++ ...tabase-method-renameCollection-option.yaml | 27 +++ ...atabase-method-renameCollection-param.yaml | 34 ++++ docs/reference/class/MongoDBCollection.txt | 1 + docs/reference/class/MongoDBDatabase.txt | 1 + .../method/MongoDBCollection-rename.txt | 79 +++++++++ .../MongoDBDatabase-renameCollection.txt | 79 +++++++++ src/Collection.php | 34 ++++ src/Database.php | 35 ++++ src/Operation/RenameCollection.php | 166 ++++++++++++++++++ tests/Collection/CollectionFunctionalTest.php | 48 +++++ .../CollectionManagementFunctionalTest.php | 43 +---- tests/Database/DatabaseFunctionalTest.php | 63 +++++++ tests/FunctionalTestCase.php | 68 +++++++ tests/GridFS/BucketFunctionalTest.php | 24 --- .../DropCollectionFunctionalTest.php | 25 --- .../RenameCollectionFunctionalTest.php | 161 +++++++++++++++++ tests/Operation/RenameCollectionTest.php | 47 +++++ 19 files changed, 897 insertions(+), 90 deletions(-) create mode 100644 docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml create mode 100644 docs/includes/apiargs-MongoDBCollection-method-rename-param.yaml create mode 100644 docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml create mode 100644 docs/includes/apiargs-MongoDBDatabase-method-renameCollection-param.yaml create mode 100644 docs/reference/method/MongoDBCollection-rename.txt create mode 100644 docs/reference/method/MongoDBDatabase-renameCollection.txt create mode 100644 src/Operation/RenameCollection.php create mode 100644 tests/Operation/RenameCollectionFunctionalTest.php create mode 100644 tests/Operation/RenameCollectionTest.php diff --git a/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml new file mode 100644 index 000000000..e0d9dbf26 --- /dev/null +++ b/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-common-option.yaml + ref: session +--- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +--- +arg_name: option +name: dropTarget +type: boolean +description: | + If ``true``, MongoDB will drop the target before renaming the collection. The + default value is ``false``. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/docs/includes/apiargs-MongoDBCollection-method-rename-param.yaml b/docs/includes/apiargs-MongoDBCollection-method-rename-param.yaml new file mode 100644 index 000000000..459b2789d --- /dev/null +++ b/docs/includes/apiargs-MongoDBCollection-method-rename-param.yaml @@ -0,0 +1,25 @@ +arg_name: param +name: $toCollectionName +type: string +description: | + The new name of the collection. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $toDatabaseName +type: string +description: | + The new database name of the collection. If a new database name is not + specified, the database of the original collection will be used. If the new + name specifies a different database, the command copies the collection + to the new database and drops the source collection. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml new file mode 100644 index 000000000..973957cf8 --- /dev/null +++ b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml @@ -0,0 +1,27 @@ +source: + file: apiargs-common-option.yaml + ref: session +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- +source: + file: apiargs-MongoDBDatabase-common-option.yaml + ref: writeConcern +post: | + This is not supported for server versions prior to 3.4 and will result in an + exception at execution time if used. +--- +arg_name: option +name: dropTarget +type: boolean +description: | + If ``true``, MongoDB will drop the target before renaming the collection. The + default value is ``false``. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-param.yaml b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-param.yaml new file mode 100644 index 000000000..3043f4dd5 --- /dev/null +++ b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-param.yaml @@ -0,0 +1,34 @@ +arg_name: param +name: $fromCollectionName +type: string +description: | + The name of the collection to rename. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $toCollectionName +type: string +description: | + The new name of the collection. +interface: phpmethod +operation: ~ +optional: false +--- +arg_name: param +name: $toDatabaseName +type: string +description: | + The new database name of the collection. If a new database name is not + specified, the current database will be used. If the new name specifies a + different database, the command copies the collection to the new database + and drops the source collection. +interface: phpmethod +operation: ~ +optional: true +--- +source: + file: apiargs-common-param.yaml + ref: $options +... diff --git a/docs/reference/class/MongoDBCollection.txt b/docs/reference/class/MongoDBCollection.txt index 4ccd2c177..57625ed02 100644 --- a/docs/reference/class/MongoDBCollection.txt +++ b/docs/reference/class/MongoDBCollection.txt @@ -91,6 +91,7 @@ Methods /reference/method/MongoDBCollection-insertOne /reference/method/MongoDBCollection-listIndexes /reference/method/MongoDBCollection-mapReduce + /reference/method/MongoDBCollection-rename /reference/method/MongoDBCollection-replaceOne /reference/method/MongoDBCollection-updateMany /reference/method/MongoDBCollection-updateOne diff --git a/docs/reference/class/MongoDBDatabase.txt b/docs/reference/class/MongoDBDatabase.txt index 464c32c50..7e7cb73d9 100644 --- a/docs/reference/class/MongoDBDatabase.txt +++ b/docs/reference/class/MongoDBDatabase.txt @@ -59,6 +59,7 @@ Methods /reference/method/MongoDBDatabase-listCollectionNames /reference/method/MongoDBDatabase-listCollections /reference/method/MongoDBDatabase-modifyCollection + /reference/method/MongoDBDatabase-renameCollection /reference/method/MongoDBDatabase-selectCollection /reference/method/MongoDBDatabase-selectGridFSBucket /reference/method/MongoDBDatabase-watch diff --git a/docs/reference/method/MongoDBCollection-rename.txt b/docs/reference/method/MongoDBCollection-rename.txt new file mode 100644 index 000000000..23a9290c3 --- /dev/null +++ b/docs/reference/method/MongoDBCollection-rename.txt @@ -0,0 +1,79 @@ +============================= +MongoDB\\Collection::rename() +============================= + +.. versionadded:: 1.10 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Collection::rename() + + Rename the collection. + + .. code-block:: php + + function rename(string $toCollectionName, ?string $toDatabaseName = null, array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBCollection-method-rename-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBCollection-method-rename-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`renameCollection +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following operation renames the ``restaurants`` collection in the ``test`` +database to ``places``: + +.. code-block:: php + + test->restaurants; + + $result = $collection->rename('places'); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#9 (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Database::renameCollection()` +- :manual:`renameCollection ` command reference in the MongoDB + manual diff --git a/docs/reference/method/MongoDBDatabase-renameCollection.txt b/docs/reference/method/MongoDBDatabase-renameCollection.txt new file mode 100644 index 000000000..558443195 --- /dev/null +++ b/docs/reference/method/MongoDBDatabase-renameCollection.txt @@ -0,0 +1,79 @@ +===================================== +MongoDB\\Database::renameCollection() +===================================== + +.. versionadded:: 1.10 + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. phpmethod:: MongoDB\\Database::renameCollection() + + Rename a collection within the current database. + + .. code-block:: php + + function renameCollection(string $fromCollectionName, string $toCollectionName, ?string $toDatabaseName = null, array $options = []): array|object + + This method has the following parameters: + + .. include:: /includes/apiargs/MongoDBDatabase-method-renameCollection-param.rst + + The ``$options`` parameter supports the following options: + + .. include:: /includes/apiargs/MongoDBDatabase-method-renameCollection-option.rst + +Return Values +------------- + +An array or object with the result document of the :manual:`renameCollection +` command. The return type will depend on the +``typeMap`` option. + +Errors/Exceptions +----------------- + +.. include:: /includes/extracts/error-unsupportedexception.rst +.. include:: /includes/extracts/error-invalidargumentexception.rst +.. include:: /includes/extracts/error-driver-runtimeexception.rst + +Example +------- + +The following example renames the ``restaurants`` collection in the ``test`` +database to ``places``: + +.. code-block:: php + + test; + + $result = $db->renameCollection('restaurants', 'places'); + + var_dump($result); + +The output would then resemble:: + + object(MongoDB\Model\BSONDocument)#8 (1) { + ["storage":"ArrayObject":private]=> + array(1) { + ["ok"]=> + float(1) + } + } + +See Also +-------- + +- :phpmethod:`MongoDB\\Collection::rename()` +- :manual:`renameCollection ` command reference in the MongoDB + manual diff --git a/src/Collection.php b/src/Collection.php index 85a1a4ecf..6634f37d9 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -53,6 +53,7 @@ use MongoDB\Operation\InsertOne; use MongoDB\Operation\ListIndexes; use MongoDB\Operation\MapReduce; +use MongoDB\Operation\RenameCollection; use MongoDB\Operation\ReplaceOne; use MongoDB\Operation\UpdateMany; use MongoDB\Operation\UpdateOne; @@ -1004,6 +1005,39 @@ public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, return $operation->execute($server); } + /** + * Renames the collection. + * + * @see RenameCollection::__construct() for supported options + * @param string $toCollectionName New name of the collection + * @param ?string $toDatabaseName New database name of the collection. Defaults to the original database. + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are not supported by the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function rename(string $toCollectionName, ?string $toDatabaseName = null, array $options = []) + { + if (! isset($toDatabaseName)) { + $toDatabaseName = $this->databaseName; + } + + if (! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = select_server($this->manager, $options); + + if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new RenameCollection($this->databaseName, $this->collectionName, $toDatabaseName, $toCollectionName, $options); + + return $operation->execute($server); + } + /** * Replaces at most one document matching the filter. * diff --git a/src/Database.php b/src/Database.php index 5d2901280..3bf414ff9 100644 --- a/src/Database.php +++ b/src/Database.php @@ -39,6 +39,7 @@ use MongoDB\Operation\ListCollectionNames; use MongoDB\Operation\ListCollections; use MongoDB\Operation\ModifyCollection; +use MongoDB\Operation\RenameCollection; use MongoDB\Operation\Watch; use Traversable; @@ -470,6 +471,40 @@ public function modifyCollection($collectionName, array $collectionOptions, arra return $operation->execute($server); } + /** + * Rename a collection within this database. + * + * @see RenameCollection::__construct() for supported options + * @param string $fromCollectionName Collection name + * @param string $toCollectionName New name of the collection + * @param ?string $toDatabaseName New database name of the collection. Defaults to the original database. + * @param array $options Additional options + * @return array|object Command result document + * @throws UnsupportedException if options are unsupported on the selected server + * @throws InvalidArgumentException for parameter/option parsing errors + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function renameCollection(string $fromCollectionName, string $toCollectionName, ?string $toDatabaseName = null, array $options = []) + { + if (! isset($toDatabaseName)) { + $toDatabaseName = $this->databaseName; + } + + if (! isset($options['typeMap'])) { + $options['typeMap'] = $this->typeMap; + } + + $server = select_server($this->manager, $options); + + if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + $options['writeConcern'] = $this->writeConcern; + } + + $operation = new RenameCollection($this->databaseName, $fromCollectionName, $toDatabaseName, $toCollectionName, $options); + + return $operation->execute($server); + } + /** * Select a collection within this database. * diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php new file mode 100644 index 000000000..e7be59c09 --- /dev/null +++ b/src/Operation/RenameCollection.php @@ -0,0 +1,166 @@ +isDefault()) { + unset($options['writeConcern']); + } + + if (isset($options['dropTarget']) && ! is_bool($options['dropTarget'])) { + throw InvalidArgumentException::invalidType('"dropTarget" option', $options['dropTarget'], 'boolean'); + } + + $this->fromNamespace = $fromDatabaseName . '.' . $fromCollectionName; + $this->toNamespace = $toDatabaseName . '.' . $toCollectionName; + $this->options = $options; + } + + /** + * Execute the operation. + * + * @see Executable::execute() + * @param Server $server + * @return array|object Command result document + * @throws UnsupportedException if writeConcern is used and unsupported + * @throws DriverRuntimeException for other driver errors (e.g. connection errors) + */ + public function execute(Server $server) + { + if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { + throw UnsupportedException::writeConcernNotSupported(); + } + + $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); + if ($inTransaction && isset($this->options['writeConcern'])) { + throw UnsupportedException::writeConcernNotSupportedInTransaction(); + } + + $cmd = [ + 'renameCollection' => $this->fromNamespace, + 'to' => $this->toNamespace, + ]; + + if (isset($this->options['dropTarget'])) { + $cmd['dropTarget'] = $this->options['dropTarget']; + } + + $cursor = $server->executeWriteCommand('admin', new Command($cmd), $this->createOptions()); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return current($cursor->toArray()); + } + + /** + * Create options for executing the command. + * + * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @return array + */ + private function createOptions() + { + $options = []; + + if (isset($this->options['session'])) { + $options['session'] = $this->options['session']; + } + + if (isset($this->options['writeConcern'])) { + $options['writeConcern'] = $this->options['writeConcern']; + } + + return $options; + } +} diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 1c6a995ac..05b71c04b 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -5,6 +5,7 @@ use Closure; use MongoDB\BSON\Javascript; use MongoDB\Collection; +use MongoDB\Database; use MongoDB\Driver\BulkWrite; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; @@ -332,6 +333,53 @@ public function testFindWithinTransaction(): void } } + public function testRenameToSameDatabase(): void + { + $toCollectionName = $this->getCollectionName() . '.renamed'; + $toCollection = new Collection($this->manager, $this->getDatabaseName(), $toCollectionName); + + $writeResult = $this->collection->insertOne(['_id' => 1]); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->collection->rename($toCollectionName, null, ['dropTarget' => true]); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionDoesNotExist($this->getCollectionName()); + $this->assertCollectionExists($toCollectionName); + + $this->assertSameDocument(['_id' => 1], $toCollection->findOne()); + $toCollection->drop(); + } + + public function testRenameToDifferentDatabase(): void + { + $toDatabaseName = $this->getDatabaseName() . '_renamed'; + $toDatabase = new Database($this->manager, $toDatabaseName); + + /* When renaming an unsharded collection, mongos requires the source + * and target database to both exist on the primary shard. In practice, this + * means we need to create the target database explicitly. + * See: https://docs.mongodb.com/manual/reference/command/renameCollection/#unsharded-collections + */ + if ($this->isShardedCluster()) { + $toDatabase->foo->insertOne(['_id' => 1]); + } + + $toCollectionName = $this->getCollectionName() . '.renamed'; + $toCollection = new Collection($this->manager, $toDatabaseName, $toCollectionName); + + $writeResult = $this->collection->insertOne(['_id' => 1]); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->collection->rename($toCollectionName, $toDatabaseName); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionDoesNotExist($this->getCollectionName()); + $this->assertCollectionExists($toCollectionName, $toDatabaseName); + + $this->assertSameDocument(['_id' => 1], $toCollection->findOne()); + + $toDatabase->drop(); + } + public function testWithOptionsInheritsOptions(): void { $collectionOptions = [ diff --git a/tests/Database/CollectionManagementFunctionalTest.php b/tests/Database/CollectionManagementFunctionalTest.php index eac00bcc7..4cb5c6107 100644 --- a/tests/Database/CollectionManagementFunctionalTest.php +++ b/tests/Database/CollectionManagementFunctionalTest.php @@ -2,15 +2,10 @@ namespace MongoDB\Tests\Database; -use InvalidArgumentException; use MongoDB\Driver\BulkWrite; use MongoDB\Model\CollectionInfo; use MongoDB\Model\CollectionInfoIterator; -use function call_user_func; -use function is_callable; -use function sprintf; - /** * Functional tests for collection management methods. */ @@ -23,7 +18,7 @@ public function testCreateCollection(): void $commandResult = $this->database->createCollection($basicCollectionName); $this->assertCommandSucceeded($commandResult); - $this->assertCollectionExists($basicCollectionName, function (CollectionInfo $info) use ($that): void { + $this->assertCollectionExists($basicCollectionName, null, function (CollectionInfo $info) use ($that): void { $that->assertFalse($info->isCapped()); }); @@ -36,7 +31,7 @@ public function testCreateCollection(): void $commandResult = $this->database->createCollection($cappedCollectionName, $cappedCollectionOptions); $this->assertCommandSucceeded($commandResult); - $this->assertCollectionExists($cappedCollectionName, function (CollectionInfo $info) use ($that): void { + $this->assertCollectionExists($cappedCollectionName, null, function (CollectionInfo $info) use ($that): void { $that->assertTrue($info->isCapped()); $that->assertEquals(100, $info->getCappedMax()); $that->assertEquals(1048576, $info->getCappedSize()); @@ -112,38 +107,4 @@ public function testListCollectionNamesWithFilter(): void $this->assertEquals($collectionName, $collection); } } - - /** - * Asserts that a collection with the given name exists in the database. - * - * An optional $callback may be provided, which should take a CollectionInfo - * argument as its first and only parameter. If a CollectionInfo matching - * the given name is found, it will be passed to the callback, which may - * perform additional assertions. - * - * @param callable $callback - */ - private function assertCollectionExists($collectionName, ?callable $callback = null): void - { - if ($callback !== null && ! is_callable($callback)) { - throw new InvalidArgumentException('$callback is not a callable'); - } - - $collections = $this->database->listCollections(); - - $foundCollection = null; - - foreach ($collections as $collection) { - if ($collection->getName() === $collectionName) { - $foundCollection = $collection; - break; - } - } - - $this->assertNotNull($foundCollection, sprintf('Found %s collection in the database', $collectionName)); - - if ($callback !== null) { - call_user_func($callback, $foundCollection); - } - } } diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 0a0f1501d..cf64531af 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -2,6 +2,7 @@ namespace MongoDB\Tests\Database; +use MongoDB\Collection; use MongoDB\Database; use MongoDB\Driver\BulkWrite; use MongoDB\Driver\Cursor; @@ -211,6 +212,68 @@ public function testModifyCollection(): void } } + public function testRenameCollectionToSameDatabase(): void + { + $toCollectionName = $this->getCollectionName() . '.renamed'; + $toCollection = new Collection($this->manager, $this->getDatabaseName(), $toCollectionName); + + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['_id' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->database->renameCollection( + $this->getCollectionName(), + $toCollectionName, + null, + ['dropTarget' => true] + ); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionDoesNotExist($this->getCollectionName()); + $this->assertCollectionExists($toCollectionName); + + $this->assertSameDocument(['_id' => 1], $toCollection->findOne()); + $toCollection->drop(); + } + + public function testRenameCollectionToDifferentDatabase(): void + { + $toDatabaseName = $this->getDatabaseName() . '_renamed'; + $toDatabase = new Database($this->manager, $toDatabaseName); + + /* When renaming an unsharded collection, mongos requires the source + * and target database to both exist on the primary shard. In practice, this + * means we need to create the target database explicitly. + * See: https://docs.mongodb.com/manual/reference/command/renameCollection/#unsharded-collections + */ + if ($this->isShardedCluster()) { + $toDatabase->foo->insertOne(['_id' => 1]); + } + + $toCollectionName = $this->getCollectionName() . '.renamed'; + $toCollection = new Collection($this->manager, $toDatabaseName, $toCollectionName); + + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['_id' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->database->renameCollection( + $this->getCollectionName(), + $toCollectionName, + $toDatabaseName + ); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionDoesNotExist($this->getCollectionName()); + $this->assertCollectionExists($toCollectionName, $toDatabaseName); + + $this->assertSameDocument(['_id' => 1], $toCollection->findOne()); + + $toDatabase->drop(); + } + public function testSelectCollectionInheritsOptions(): void { $databaseOptions = [ diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 44c51d8c6..38877c92b 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -16,16 +16,19 @@ use MongoDB\Operation\CreateCollection; use MongoDB\Operation\DatabaseCommand; use MongoDB\Operation\DropCollection; +use MongoDB\Operation\ListCollections; use stdClass; use UnexpectedValueException; use function array_merge; +use function call_user_func; use function count; use function current; use function explode; use function getenv; use function implode; use function is_array; +use function is_callable; use function is_object; use function is_string; use function key; @@ -147,6 +150,71 @@ protected function assertCollectionCount($namespace, $count): void $this->assertEquals($count, $document['n']); } + /** + * Asserts that a collection with the given name does not exist on the + * server. + * + * $databaseName defaults to TestCase::getDatabaseName() if unspecified. + */ + protected function assertCollectionDoesNotExist(string $collectionName, ?string $databaseName = null): void + { + if (! isset($databaseName)) { + $databaseName = $this->getDatabaseName(); + } + + $operation = new ListCollections($this->getDatabaseName()); + $collections = $operation->execute($this->getPrimaryServer()); + + $foundCollection = null; + + foreach ($collections as $collection) { + if ($collection->getName() === $collectionName) { + $foundCollection = $collection; + break; + } + } + + $this->assertNull($foundCollection, sprintf('Collection %s exists', $collectionName)); + } + + /** + * Asserts that a collection with the given name exists on the server. + * + * $databaseName defaults to TestCase::getDatabaseName() if unspecified. + * An optional $callback may be provided, which should take a CollectionInfo + * argument as its first and only parameter. If a CollectionInfo matching + * the given name is found, it will be passed to the callback, which may + * perform additional assertions. + */ + protected function assertCollectionExists(string $collectionName, ?string $databaseName = null, ?callable $callback = null): void + { + if (! isset($databaseName)) { + $databaseName = $this->getDatabaseName(); + } + + if ($callback !== null && ! is_callable($callback)) { + throw new InvalidArgumentException('$callback is not a callable'); + } + + $operation = new ListCollections($databaseName); + $collections = $operation->execute($this->getPrimaryServer()); + + $foundCollection = null; + + foreach ($collections as $collection) { + if ($collection->getName() === $collectionName) { + $foundCollection = $collection; + break; + } + } + + $this->assertNotNull($foundCollection, sprintf('Found %s collection in the database', $collectionName)); + + if ($callback !== null) { + call_user_func($callback, $foundCollection); + } + } + protected function assertCommandSucceeded($document): void { $document = is_object($document) ? (array) $document : $document; diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 6ed7f27c8..79c5f345f 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -13,7 +13,6 @@ use MongoDB\GridFS\Exception\StreamException; use MongoDB\Model\BSONDocument; use MongoDB\Model\IndexInfo; -use MongoDB\Operation\ListCollections; use MongoDB\Operation\ListIndexes; use PHPUnit\Framework\Error\Warning; @@ -773,29 +772,6 @@ public function testDanglingOpenWritableStream(): void $this->assertSame('', $output); } - /** - * Asserts that a collection with the given name does not exist on the - * server. - * - * @param string $collectionName - */ - private function assertCollectionDoesNotExist(string $collectionName): void - { - $operation = new ListCollections($this->getDatabaseName()); - $collections = $operation->execute($this->getPrimaryServer()); - - $foundCollection = null; - - foreach ($collections as $collection) { - if ($collection->getName() === $collectionName) { - $foundCollection = $collection; - break; - } - } - - $this->assertNull($foundCollection, sprintf('Collection %s exists', $collectionName)); - } - /** * Asserts that an index with the given name exists for the collection. * diff --git a/tests/Operation/DropCollectionFunctionalTest.php b/tests/Operation/DropCollectionFunctionalTest.php index 50fcc3ac6..696cfefcf 100644 --- a/tests/Operation/DropCollectionFunctionalTest.php +++ b/tests/Operation/DropCollectionFunctionalTest.php @@ -4,10 +4,8 @@ use MongoDB\Operation\DropCollection; use MongoDB\Operation\InsertOne; -use MongoDB\Operation\ListCollections; use MongoDB\Tests\CommandObserver; -use function sprintf; use function version_compare; class DropCollectionFunctionalTest extends FunctionalTestCase @@ -81,27 +79,4 @@ function (array $event): void { } ); } - - /** - * Asserts that a collection with the given name does not exist on the - * server. - * - * @param string $collectionName - */ - private function assertCollectionDoesNotExist(string $collectionName): void - { - $operation = new ListCollections($this->getDatabaseName()); - $collections = $operation->execute($this->getPrimaryServer()); - - $foundCollection = null; - - foreach ($collections as $collection) { - if ($collection->getName() === $collectionName) { - $foundCollection = $collection; - break; - } - } - - $this->assertNull($foundCollection, sprintf('Collection %s exists', $collectionName)); - } } diff --git a/tests/Operation/RenameCollectionFunctionalTest.php b/tests/Operation/RenameCollectionFunctionalTest.php new file mode 100644 index 000000000..c14969681 --- /dev/null +++ b/tests/Operation/RenameCollectionFunctionalTest.php @@ -0,0 +1,161 @@ +toCollectionName = $this->getCollectionName() . '.renamed'; + $operation = new DropCollection($this->getDatabaseName(), $this->toCollectionName); + $operation->execute($this->getPrimaryServer()); + } + + public function tearDown(): void + { + if ($this->hasFailed()) { + return; + } + + $operation = new DropCollection($this->getDatabaseName(), $this->toCollectionName); + $operation->execute($this->getPrimaryServer()); + + parent::tearDown(); + } + + public function testDefaultWriteConcernIsOmitted(): void + { + (new CommandObserver())->observe( + function (): void { + $server = $this->getPrimaryServer(); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new RenameCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + $this->getDatabaseName(), + $this->toCollectionName, + ['writeConcern' => $this->createDefaultWriteConcern()] + ); + + $operation->execute($server); + }, + function (array $event): void { + $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand()); + } + ); + } + + public function testRenameCollectionToNonexistentTarget(): void + { + $server = $this->getPrimaryServer(); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['_id' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new RenameCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + $this->getDatabaseName(), + $this->toCollectionName + ); + $commandResult = $operation->execute($server); + + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionDoesNotExist($this->getCollectionName()); + $this->assertCollectionExists($this->toCollectionName); + + $operation = new FindOne($this->getDatabaseName(), $this->toCollectionName, []); + $this->assertSameDocument(['_id' => 1], $operation->execute($server)); + } + + public function testRenameCollectionExistingTarget(): void + { + $server = $this->getPrimaryServer(); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['_id' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->toCollectionName, ['_id' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $this->expectException(CommandException::class); + $this->expectExceptionCode(self::$errorCodeNamespaceExists); + $operation = new RenameCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + $this->getDatabaseName(), + $this->toCollectionName + ); + $operation->execute($server); + } + + public function testRenameNonexistentCollection(): void + { + $this->expectException(CommandException::class); + $this->expectExceptionCode(self::$errorCodeNamespaceNotFound); + $operation = new RenameCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + $this->getDatabaseName(), + $this->toCollectionName + ); + $operation->execute($this->getPrimaryServer()); + } + + public function testSessionOption(): void + { + if (version_compare($this->getServerVersion(), '3.6.0', '<')) { + $this->markTestSkipped('Sessions are not supported'); + } + + (new CommandObserver())->observe( + function (): void { + $server = $this->getPrimaryServer(); + + $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); + $writeResult = $insertOne->execute($server); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $operation = new RenameCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + $this->getDatabaseName(), + $this->toCollectionName, + ['session' => $this->createSession()] + ); + + $operation->execute($server); + }, + function (array $event): void { + $this->assertObjectHasAttribute('lsid', $event['started']->getCommand()); + } + ); + } +} diff --git a/tests/Operation/RenameCollectionTest.php b/tests/Operation/RenameCollectionTest.php new file mode 100644 index 000000000..f25eea78d --- /dev/null +++ b/tests/Operation/RenameCollectionTest.php @@ -0,0 +1,47 @@ +expectException(InvalidArgumentException::class); + new RenameCollection( + $this->getDatabaseName(), + $this->getCollectionName(), + $this->getDatabaseName(), + $this->getCollectionName() . '.renamed', + $options + ); + } + + public function provideInvalidConstructorOptions() + { + $options = []; + + foreach ($this->getInvalidSessionValues() as $value) { + $options[][] = ['session' => $value]; + } + + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['typeMap' => $value]; + } + + foreach ($this->getInvalidWriteConcernValues() as $value) { + $options[][] = ['writeConcern' => $value]; + } + + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['dropTarget' => $value]; + } + + return $options; + } +} From 95d84fbeae96f967bb8c16614a6ef405332eb805 Mon Sep 17 00:00:00 2001 From: Tanli Su <46271307+tanlisu@users.noreply.github.com> Date: Tue, 27 Jul 2021 13:38:44 -0400 Subject: [PATCH 072/321] PHPLIB-682: Add test for Database::dropCollection() (#847) --- tests/Collection/CollectionFunctionalTest.php | 2 +- tests/Database/DatabaseFunctionalTest.php | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 05b71c04b..fd8018e1d 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -264,7 +264,7 @@ public function testDrop(): void $commandResult = $this->collection->drop(); $this->assertCommandSucceeded($commandResult); - $this->assertCollectionCount($this->getNamespace(), 0); + $this->assertCollectionDoesNotExist($this->getCollectionName()); } /** diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index cf64531af..72a7cadaf 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -159,6 +159,19 @@ public function testDrop(): void $this->assertCollectionCount($this->getNamespace(), 0); } + public function testDropCollection(): void + { + $bulkWrite = new BulkWrite(); + $bulkWrite->insert(['x' => 1]); + + $writeResult = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite); + $this->assertEquals(1, $writeResult->getInsertedCount()); + + $commandResult = $this->database->dropCollection($this->getCollectionName()); + $this->assertCommandSucceeded($commandResult); + $this->assertCollectionDoesNotExist($this->getCollectionName()); + } + public function testGetSelectsCollectionAndInheritsOptions(): void { $databaseOptions = ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; From 60bd25a16ae3b78b08d03b74de05282d2591fd3f Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 2 Aug 2021 09:52:39 -0400 Subject: [PATCH 073/321] PHPLIB-664, PHPLIB-676, and PHPLIB-703: APM redaction and observeSensitiveCommands (#848) * PHPLIB-664 and PHPLIB-676: Sync unified command-monitoring tests Implements observeSensitiveCommands, which was introduced in unified test format schema version 1.5. Synced with mongodb/specifications@289f4053106261bae80ba098c8afeb885b26acc2 * PHPLIB-703: Integration tests for observeSensitiveCommands Synced with mongodb/specifications@6847048c551431c8a328b9c1f0deeec158160d20 Co-authored-by: Andreas Braun Co-authored-by: Tanli Su <46271307+tanlisu@users.noreply.github.com> --- tests/UnifiedSpecTests/Context.php | 15 +- tests/UnifiedSpecTests/EventObserver.php | 88 ++- tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 + tests/UnifiedSpecTests/UnifiedTestRunner.php | 2 +- .../command-monitoring/redacted-commands.json | 659 +++++++++++++++++ .../valid-pass/observeSensitiveCommands.json | 691 ++++++++++++++++++ 6 files changed, 1443 insertions(+), 25 deletions(-) create mode 100644 tests/UnifiedSpecTests/command-monitoring/redacted-commands.json create mode 100644 tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index b037a7eff..059b40205 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -248,11 +248,21 @@ static function (string $tag): array { private function createClient(string $id, stdClass $o): void { - Util::assertHasOnlyKeys($o, ['id', 'uriOptions', 'useMultipleMongoses', 'observeEvents', 'ignoreCommandMonitoringEvents', 'serverApi', 'storeEventsAsEntities']); + Util::assertHasOnlyKeys($o, [ + 'id', + 'uriOptions', + 'useMultipleMongoses', + 'observeEvents', + 'ignoreCommandMonitoringEvents', + 'observeSensitiveCommands', + 'serverApi', + 'storeEventsAsEntities', + ]); $useMultipleMongoses = $o->useMultipleMongoses ?? null; $observeEvents = $o->observeEvents ?? null; $ignoreCommandMonitoringEvents = $o->ignoreCommandMonitoringEvents ?? []; + $observeSensitiveCommands = $o->observeSensitiveCommands ?? false; $serverApi = $o->serverApi ?? null; $storeEventsAsEntities = $o->storeEventsAsEntities ?? null; @@ -289,8 +299,9 @@ private function createClient(string $id, stdClass $o): void if (isset($observeEvents)) { assertIsArray($observeEvents); assertIsArray($ignoreCommandMonitoringEvents); + assertIsBool($observeSensitiveCommands); - $this->eventObserversByClient[$id] = new EventObserver($observeEvents, $ignoreCommandMonitoringEvents, $id, $this); + $this->eventObserversByClient[$id] = new EventObserver($observeEvents, $ignoreCommandMonitoringEvents, $observeSensitiveCommands, $id, $this); } if (isset($storeEventsAsEntities)) { diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index 1be557bf7..d942cf1e4 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -12,7 +12,6 @@ use PHPUnit\Framework\Assert; use stdClass; -use function array_fill_keys; use function array_reverse; use function count; use function current; @@ -38,22 +37,36 @@ */ final class EventObserver implements CommandSubscriber { - /** @var array */ - private static $defaultIgnoreCommands = [ - // failPoint and targetedFailPoint operations - 'configureFailPoint', - // See: https://github.com/mongodb/specifications/blob/master/source/command-monitoring/command-monitoring.rst#security - 'authenticate', - 'saslStart', - 'saslContinue', - 'getnonce', - 'createUser', - 'updateUser', - 'copydbgetnonce', - 'copydbsaslstart', - 'copydb', - 'isMaster', - 'hello', + /** + * These commands are always considered sensitive (i.e. command and reply + * documents should be redacted). + * + * @see https://github.com/mongodb/specifications/blob/master/source/command-monitoring/command-monitoring.rst#security + * @var array + */ + private static $sensitiveCommands = [ + 'authenticate' => 1, + 'saslStart' => 1, + 'saslContinue' => 1, + 'getnonce' => 1, + 'createUser' => 1, + 'updateUser' => 1, + 'copydbgetnonce' => 1, + 'copydbsaslstart' => 1, + 'copydb' => 1, + ]; + + /** + * These commands are only considered sensitive when the command or reply + * document includes a speculativeAuthenticate field. + * + * @see https://github.com/mongodb/specifications/blob/master/source/command-monitoring/command-monitoring.rst#security + * @var array + */ + private static $sensitiveCommandsWithSpeculativeAuthenticate = [ + 'ismaster' => 1, + 'isMaster' => 1, + 'hello' => 1, ]; /** @var array */ @@ -72,13 +85,21 @@ final class EventObserver implements CommandSubscriber /** @var Context */ private $context; - /** @var array */ - private $ignoreCommands = []; + /** + * The configureFailPoint command (used by failPoint and targetedFailPoint + * operations) is always ignored. + * + * @var array + */ + private $ignoreCommands = ['configureFailPoint' => 1]; /** @var array */ private $observeEvents = []; - public function __construct(array $observeEvents, array $ignoreCommands, string $clientId, Context $context) + /** @var bool */ + private $observeSensitiveCommands; + + public function __construct(array $observeEvents, array $ignoreCommands, bool $observeSensitiveCommands, string $clientId, Context $context) { assertNotEmpty($observeEvents); @@ -88,13 +109,12 @@ public function __construct(array $observeEvents, array $ignoreCommands, string $this->observeEvents[self::$supportedEvents[$event]] = 1; } - $this->ignoreCommands = array_fill_keys(self::$defaultIgnoreCommands, 1); - foreach ($ignoreCommands as $command) { assertIsString($command); $this->ignoreCommands[$command] = 1; } + $this->observeSensitiveCommands = $observeSensitiveCommands; $this->clientId = $clientId; $this->context = $context; } @@ -270,6 +290,30 @@ private function handleEvent($event): void return; } + if (! $this->observeSensitiveCommands && $this->isSensitiveCommand($event)) { + return; + } + $this->actualEvents[] = $event; } + + /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ + private function isSensitiveCommand($event): bool + { + if (isset(self::$sensitiveCommands[$event->getCommandName()])) { + return true; + } + + /* If the command or reply included a speculativeAuthenticate field, + * libmongoc will already have redacted it (CDRIVER-4000). Therefore, we + * can infer that the command was sensitive if its command or reply is + * empty. */ + if (isset(self::$sensitiveCommandsWithSpeculativeAuthenticate[$event->getCommandName()])) { + $commandOrReply = $event instanceof CommandStartedEvent ? $event->getCommand() : $event->getReply(); + + return (array) $commandOrReply === []; + } + + return false; + } } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index ec112a730..100a20517 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -97,6 +97,19 @@ public function provideCollectionManagementTests() return $this->provideTests(__DIR__ . '/collection-management/*.json'); } + /** + * @dataProvider provideCommandMonitoringTests + */ + public function testCommandMonitoring(UnifiedTestCase $test): void + { + self::$runner->run($test); + } + + public function provideCommandMonitoringTests() + { + return $this->provideTests(__DIR__ . '/command-monitoring/*.json'); + } + /** * @dataProvider provideCrudTests */ diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 03d607419..e39246958 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -46,7 +46,7 @@ final class UnifiedTestRunner public const SERVER_ERROR_UNAUTHORIZED = 13; public const MIN_SCHEMA_VERSION = '1.0'; - public const MAX_SCHEMA_VERSION = '1.4'; + public const MAX_SCHEMA_VERSION = '1.5'; /** @var MongoDB\Client */ private $internalClient; diff --git a/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json b/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json new file mode 100644 index 000000000..0f85dc3e9 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json @@ -0,0 +1,659 @@ +{ + "description": "redacted-commands", + "schemaVersion": "1.5", + "runOnRequirements": [ + { + "minServerVersion": "5.0", + "auth": false + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent" + ], + "observeSensitiveCommands": true + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + } + ], + "tests": [ + { + "description": "authenticate", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "authenticate", + "command": { + "authenticate": 1, + "mechanism": "MONGODB-X509", + "user": "CN=myName,OU=myOrgUnit,O=myOrg,L=myLocality,ST=myState,C=myCountry", + "db": "$external" + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "authenticate", + "command": { + "authenticate": { + "$$exists": false + }, + "mechanism": { + "$$exists": false + }, + "user": { + "$$exists": false + }, + "db": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "saslStart", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "saslStart", + "command": { + "saslStart": 1, + "payload": "definitely-invalid-payload", + "db": "admin" + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "saslStart", + "command": { + "saslStart": { + "$$exists": false + }, + "payload": { + "$$exists": false + }, + "db": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "saslContinue", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "saslContinue", + "command": { + "saslContinue": 1, + "conversationId": 0, + "payload": "definitely-invalid-payload" + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "saslContinue", + "command": { + "saslContinue": { + "$$exists": false + }, + "conversationId": { + "$$exists": false + }, + "payload": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "getnonce", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "getnonce", + "command": { + "getnonce": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "getnonce", + "command": { + "getnonce": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "getnonce", + "reply": { + "ok": { + "$$exists": false + }, + "nonce": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "createUser", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "createUser", + "command": { + "createUser": "private", + "pwd": {}, + "roles": [] + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "createUser", + "command": { + "createUser": { + "$$exists": false + }, + "pwd": { + "$$exists": false + }, + "roles": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "updateUser", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "updateUser", + "command": { + "updateUser": "private", + "pwd": {}, + "roles": [] + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "updateUser", + "command": { + "updateUser": { + "$$exists": false + }, + "pwd": { + "$$exists": false + }, + "roles": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "copydbgetnonce", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "copydbgetnonce", + "command": { + "copydbgetnonce": "private" + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "copydbgetnonce", + "command": { + "copydbgetnonce": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "copydbsaslstart", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "copydbsaslstart", + "command": { + "copydbsaslstart": "private" + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "copydbsaslstart", + "command": { + "copydbsaslstart": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "copydb", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "copydb", + "command": { + "copydb": "private" + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "copydb", + "command": { + "copydb": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "hello with speculative authenticate", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "hello", + "command": { + "hello": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "hello", + "reply": { + "isWritablePrimary": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "legacy hello with speculative authenticate", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "ismaster", + "command": { + "ismaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "ismaster", + "reply": { + "ismaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "isMaster", + "command": { + "isMaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "isMaster", + "reply": { + "ismaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "hello without speculative authenticate is not redacted", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "hello", + "reply": { + "isWritablePrimary": { + "$$exists": true + } + } + } + } + ] + } + ] + }, + { + "description": "legacy hello without speculative authenticate is not redacted", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "ismaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "isMaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json b/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json new file mode 100644 index 000000000..411ca19c5 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json @@ -0,0 +1,691 @@ +{ + "description": "observeSensitiveCommands", + "schemaVersion": "1.5", + "runOnRequirements": [ + { + "auth": false + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent" + ], + "observeSensitiveCommands": true + } + }, + { + "client": { + "id": "client1", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent" + ], + "observeSensitiveCommands": false + } + }, + { + "client": { + "id": "client2", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "observeSensitiveCommands" + } + }, + { + "database": { + "id": "database1", + "client": "client1", + "databaseName": "observeSensitiveCommands" + } + }, + { + "database": { + "id": "database2", + "client": "client2", + "databaseName": "observeSensitiveCommands" + } + } + ], + "tests": [ + { + "description": "getnonce is observed with observeSensitiveCommands=true", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "getnonce", + "command": { + "getnonce": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "getnonce", + "command": { + "getnonce": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "getnonce", + "reply": { + "ok": { + "$$exists": false + }, + "nonce": { + "$$exists": false + } + } + } + } + ] + } + ] + }, + { + "description": "getnonce is not observed with observeSensitiveCommands=false", + "operations": [ + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "getnonce", + "command": { + "getnonce": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client1", + "events": [] + } + ] + }, + { + "description": "getnonce is not observed by default", + "operations": [ + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "getnonce", + "command": { + "getnonce": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client2", + "events": [] + } + ] + }, + { + "description": "hello with speculativeAuthenticate", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "hello", + "command": { + "hello": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "hello", + "reply": { + "isWritablePrimary": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + } + ] + }, + { + "client": "client1", + "events": [] + }, + { + "client": "client2", + "events": [] + } + ] + }, + { + "description": "hello without speculativeAuthenticate is always observed", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + }, + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + }, + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "hello", + "reply": { + "isWritablePrimary": { + "$$exists": true + } + } + } + } + ] + }, + { + "client": "client1", + "events": [ + { + "commandStartedEvent": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "hello", + "reply": { + "isWritablePrimary": { + "$$exists": true + } + } + } + } + ] + }, + { + "client": "client2", + "events": [ + { + "commandStartedEvent": { + "commandName": "hello", + "command": { + "hello": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "hello", + "reply": { + "isWritablePrimary": { + "$$exists": true + } + } + } + } + ] + } + ] + }, + { + "description": "legacy hello with speculativeAuthenticate", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + }, + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1, + "speculativeAuthenticate": { + "saslStart": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "ismaster", + "command": { + "ismaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "ismaster", + "reply": { + "ismaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "isMaster", + "command": { + "isMaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + }, + { + "commandSucceededEvent": { + "commandName": "isMaster", + "reply": { + "ismaster": { + "$$exists": false + }, + "speculativeAuthenticate": { + "$$exists": false + } + } + } + } + ] + }, + { + "client": "client1", + "events": [] + }, + { + "client": "client2", + "events": [] + } + ] + }, + { + "description": "legacy hello without speculativeAuthenticate is always observed", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + }, + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "name": "runCommand", + "object": "database1", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + }, + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "name": "runCommand", + "object": "database2", + "arguments": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "ismaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "isMaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + } + ] + }, + { + "client": "client1", + "events": [ + { + "commandStartedEvent": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "ismaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "isMaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + } + ] + }, + { + "client": "client2", + "events": [ + { + "commandStartedEvent": { + "commandName": "ismaster", + "command": { + "ismaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "ismaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "isMaster", + "command": { + "isMaster": 1 + } + } + }, + { + "commandSucceededEvent": { + "commandName": "isMaster", + "reply": { + "ismaster": { + "$$exists": true + } + } + } + } + ] + } + ] + } + ] +} From 0be1877bd979b668026f89c326141b2820e1c4e1 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Sat, 7 Aug 2021 05:02:10 -0400 Subject: [PATCH 074/321] Document process for bumping dev-master branch-alias and bump to 1.10-dev (#852) --- CONTRIBUTING.md | 31 +++++++++++++++++++++++++++++++ composer.json | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cdf77489c..db1db742b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -83,6 +83,37 @@ repository: informational log messages with the `--level warning` option. * Generated documentation may be found in the `build/master/html` directory. +## Creating a maintenance branch and updating master branch alias + +After releasing a new major or minor version (e.g. 1.9.0), a maintenance branch +(e.g. v1.9) should be created. Any development towards a patch release (e.g. +1.9.1) would then be done within that branch and any development for the next +major or minor release can continue in master. + +After creating a maintenance branch, the `extra.branch-alias.dev-master` field +in the master branch's `composer.json` file should be updated. For example, +after branching v1.9, `composer.json` in the master branch may still read: + +``` +"branch-alias": { + "dev-master": "1.9.x-dev" +} +``` + +The above would be changed to: + +``` +"branch-alias": { + "dev-master": "1.10.x-dev" +} +``` + +Commit this change: + +``` +$ git commit -m "Master is now 1.10-dev" composer.json +``` + ## Releasing The follow steps outline the release process for a maintenance branch (e.g. diff --git a/composer.json b/composer.json index e5b5201f8..ff50b3177 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.9.x-dev" + "dev-master": "1.10.x-dev" } } } From f517df87fbf1b2a6995fa0fd84ac01bd17ae0e3a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 10 Aug 2021 11:19:15 -0400 Subject: [PATCH 075/321] PHPLIB-694: Spec tests for snapshot sessions (#851) * PHPLIB-694: Spec tests for snapshot sessions Syncs tests with mongodb/specifications@ac4935338a65d7f3370befd5c245e1be68f9eeba * Bumps ext-mongodb requirement to 1.11-dev This is necessary to pull in changes from PHPC-1761 for testing snapshot sessions. --- .evergreen/config.yml | 26 +- composer.json | 2 +- tests/UnifiedSpecTests/Context.php | 6 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 13 + ...t-sessions-not-supported-client-error.json | 128 +++ ...t-sessions-not-supported-server-error.json | 187 ++++ .../snapshot-sessions-unsupported-ops.json | 493 +++++++++ .../sessions/snapshot-sessions.json | 993 ++++++++++++++++++ 8 files changed, 1833 insertions(+), 15 deletions(-) create mode 100644 tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-client-error.json create mode 100644 tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-server-error.json create mode 100644 tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json create mode 100644 tests/UnifiedSpecTests/sessions/snapshot-sessions.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 37ff9b8b6..1c2d6a43a 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -473,14 +473,14 @@ axes: # display_name: "1.10.0" # variables: # EXTENSION_VERSION: "1.10.0" - - id: "latest-stable" - display_name: "Latest Stable (1.10.x)" - variables: - EXTENSION_VERSION: "stable" - - id: "upcoming-stable" - display_name: "1.10-dev" - variables: - EXTENSION_BRANCH: "v1.10" +# - id: "latest-stable" +# display_name: "Latest Stable (1.10.x)" +# variables: +# EXTENSION_VERSION: "stable" +# - id: "upcoming-stable" +# display_name: "1.10-dev" +# variables: +# EXTENSION_BRANCH: "v1.10" - id: "latest-dev" display_name: "1.11-dev (master)" variables: @@ -574,7 +574,7 @@ buildvariants: # Tests all PHP versions on all operating systems. # Only tests against latest MongoDB and ext-mongodb versions - matrix_name: "test-php-versions" - matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest-stable" } + matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest-dev" } exclude_spec: # rhel71-power8 fails due to not reaching pecl - { "os-php7": "rhel71-power8", "php-versions": "*", edge-versions: "*", "driver-versions": "*" } @@ -600,7 +600,7 @@ buildvariants: # Only tests on Ubuntu 18.04, with latest stable PHP and driver versions # Tests against various topologies - matrix_name: "test-mongodb-versions" - matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest-stable" } + matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest-dev" } display_name: "MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" @@ -611,7 +611,7 @@ buildvariants: # Enables --prefer-lowest for composer to test oldest dependencies against all server versions # TODO: driver-versions can be changed back to lowest-supported when that version is enabled in the axis - matrix_name: "test-dependencies" - matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "latest-stable" } + matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "latest-dev" } display_name: "Dependencies: ${dependencies}, MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" @@ -619,14 +619,14 @@ buildvariants: - name: "test-sharded_cluster" - matrix_name: "atlas-data-lake-test" - matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-dev" } display_name: "Atlas Data Lake test" run_on: rhel70 tasks: - name: "test-atlas-data-lake" - matrix_name: "test-versioned-api" - matrix_spec: { "php-edge-versions": "latest-stable", "versions": ["5.0", "latest"], "driver-versions": "latest-stable" } + matrix_spec: { "php-edge-versions": "latest-stable", "versions": ["5.0", "latest"], "driver-versions": "latest-dev" } display_name: "Versioned API - ${versions}" run_on: rhel70 tasks: diff --git a/composer.json b/composer.json index ff50b3177..4493881cc 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.1 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.10.0", + "ext-mongodb": "^1.11.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 059b40205..e8e56189e 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -452,7 +452,7 @@ private static function prepareBucketOptions(array $options): array private static function prepareSessionOptions(array $options): array { - Util::assertHasOnlyKeys($options, ['causalConsistency', 'defaultTransactionOptions']); + Util::assertHasOnlyKeys($options, ['causalConsistency', 'defaultTransactionOptions', 'snapshot']); if (array_key_exists('causalConsistency', $options)) { assertIsBool($options['causalConsistency']); @@ -463,6 +463,10 @@ private static function prepareSessionOptions(array $options): array $options['defaultTransactionOptions'] = self::prepareDefaultTransactionOptions((array) $options['defaultTransactionOptions']); } + if (array_key_exists('snapshot', $options)) { + assertIsBool($options['snapshot']); + } + return $options; } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 100a20517..fa745979c 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -136,6 +136,19 @@ public function provideGridFSTests() return $this->provideTests(__DIR__ . '/gridfs/*.json'); } + /** + * @dataProvider provideSessionsTests + */ + public function testSessions(UnifiedTestCase $test): void + { + self::$runner->run($test); + } + + public function provideSessionsTests() + { + return $this->provideTests(__DIR__ . '/sessions/*.json'); + } + /** * @dataProvider provideTransactionsTests */ diff --git a/tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-client-error.json b/tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-client-error.json new file mode 100644 index 000000000..208e4cfe6 --- /dev/null +++ b/tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-client-error.json @@ -0,0 +1,128 @@ +{ + "description": "snapshot-sessions-not-supported-client-error", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "maxServerVersion": "4.4.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "session": { + "id": "session0", + "client": "client0", + "sessionOptions": { + "snapshot": true + } + } + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "Client error on find with snapshot", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": {} + }, + "expectError": { + "isClientError": true, + "errorContains": "Snapshot reads require MongoDB 5.0 or later" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Client error on aggregate with snapshot", + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "session": "session0", + "pipeline": [] + }, + "expectError": { + "isClientError": true, + "errorContains": "Snapshot reads require MongoDB 5.0 or later" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Client error on distinct with snapshot", + "operations": [ + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session0" + }, + "expectError": { + "isClientError": true, + "errorContains": "Snapshot reads require MongoDB 5.0 or later" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-server-error.json b/tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-server-error.json new file mode 100644 index 000000000..79213f314 --- /dev/null +++ b/tests/UnifiedSpecTests/sessions/snapshot-sessions-not-supported-server-error.json @@ -0,0 +1,187 @@ +{ + "description": "snapshot-sessions-not-supported-server-error", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "5.0", + "topologies": [ + "single" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "session": { + "id": "session0", + "client": "client0", + "sessionOptions": { + "snapshot": true + } + } + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "Server returns an error on find with snapshot", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on aggregate with snapshot", + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "session": "session0", + "pipeline": [] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on distinct with snapshot", + "operations": [ + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session0" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "distinct" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json b/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json new file mode 100644 index 000000000..1021b7f26 --- /dev/null +++ b/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json @@ -0,0 +1,493 @@ +{ + "description": "snapshot-sessions-unsupported-ops", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "5.0", + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "session": { + "id": "session0", + "client": "client0", + "sessionOptions": { + "snapshot": true + } + } + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "Server returns an error on insertOne with snapshot", + "runOnRequirements": [ + { + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 22, + "x": 22 + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on insertMany with snapshot", + "runOnRequirements": [ + { + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "session": "session0", + "documents": [ + { + "_id": 22, + "x": 22 + }, + { + "_id": 33, + "x": 33 + } + ] + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on deleteOne with snapshot", + "runOnRequirements": [ + { + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": {} + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on updateOne with snapshot", + "runOnRequirements": [ + { + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on findOneAndUpdate with snapshot", + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "findAndModify" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on listDatabases with snapshot", + "operations": [ + { + "name": "listDatabases", + "object": "client0", + "arguments": { + "session": "session0" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listDatabases": 1, + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "listDatabases" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on listCollections with snapshot", + "operations": [ + { + "name": "listCollections", + "object": "database0", + "arguments": { + "session": "session0" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listCollections": 1, + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on listIndexes with snapshot", + "operations": [ + { + "name": "listIndexes", + "object": "collection0", + "arguments": { + "session": "session0" + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listIndexes": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "listIndexes" + } + } + ] + } + ] + }, + { + "description": "Server returns an error on runCommand with snapshot", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "session": "session0", + "commandName": "listCollections", + "command": { + "listCollections": 1 + } + }, + "expectError": { + "isError": true, + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listCollections": 1, + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandFailedEvent": { + "commandName": "listCollections" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/sessions/snapshot-sessions.json b/tests/UnifiedSpecTests/sessions/snapshot-sessions.json new file mode 100644 index 000000000..75b577b03 --- /dev/null +++ b/tests/UnifiedSpecTests/sessions/snapshot-sessions.json @@ -0,0 +1,993 @@ +{ + "description": "snapshot-sessions", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "5.0", + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "findAndModify", + "insert", + "update" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0", + "collectionOptions": { + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "session": { + "id": "session0", + "client": "client0", + "sessionOptions": { + "snapshot": true + } + } + }, + { + "session": { + "id": "session1", + "client": "client0", + "sessionOptions": { + "snapshot": true + } + } + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "Find operation with snapshot", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 1, + "x": 12 + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session1", + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 12 + } + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 1, + "x": 13 + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 13 + } + ] + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session1", + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 12 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + } + ] + } + ] + }, + { + "description": "Distinct operation with snapshot", + "operations": [ + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session0" + }, + "expectResult": [ + 11 + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 2, + "x": 12 + } + }, + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session1" + }, + "expectResult": [ + 11, + 12 + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 2, + "x": 13 + } + }, + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {} + }, + "expectResult": [ + 11, + 13 + ] + }, + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session0" + }, + "expectResult": [ + 11 + ] + }, + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session1" + }, + "expectResult": [ + 11, + 12 + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + } + ] + } + ] + }, + { + "description": "Aggregate operation with snapshot", + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "session": "session0" + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 1, + "x": 12 + } + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "session": "session1" + }, + "expectResult": [ + { + "_id": 1, + "x": 12 + } + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 1, + "x": 13 + } + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ] + }, + "expectResult": [ + { + "_id": 1, + "x": 13 + } + ] + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "session": "session0" + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "session": "session1" + }, + "expectResult": [ + { + "_id": 1, + "x": 12 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + } + ] + } + ] + }, + { + "description": "countDocuments operation with snapshot", + "operations": [ + { + "name": "countDocuments", + "object": "collection0", + "arguments": { + "filter": {}, + "session": "session0" + }, + "expectResult": 2 + }, + { + "name": "countDocuments", + "object": "collection0", + "arguments": { + "filter": {}, + "session": "session0" + }, + "expectResult": 2 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + } + ] + } + ] + }, + { + "description": "Mixed operation with snapshot", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "After" + }, + "expectResult": { + "_id": 1, + "x": 12 + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectResult": [ + { + "_id": 1, + "x": 12 + } + ] + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": 1 + } + } + ], + "session": "session0" + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + }, + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "session": "session0" + }, + "expectResult": [ + 11 + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "distinct": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + } + ] + } + ] + }, + { + "description": "Write commands with snapshot session do not affect snapshot reads", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 22, + "x": 33 + } + } + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "session": "session0" + }, + "expectResult": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": true + } + } + } + } + } + ] + } + ] + }, + { + "description": "First snapshot read does not send atClusterTime", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "session": "session0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "collection0", + "readConcern": { + "level": "snapshot", + "atClusterTime": { + "$$exists": false + } + } + }, + "commandName": "find", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "StartTransaction fails in snapshot session", + "operations": [ + { + "name": "startTransaction", + "object": "session0", + "expectError": { + "isError": true, + "isClientError": true, + "errorContains": "Transactions are not supported in snapshot sessions" + } + } + ] + } + ] +} From 18c4050b6103e087755123912139be57efce6733 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 11 Aug 2021 11:43:45 +0200 Subject: [PATCH 076/321] PHPLIB-706 Fix syntax error in docs example (#853) --- docs/tutorial/collation.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorial/collation.txt b/docs/tutorial/collation.txt index 0b1bfabd9..7145de0d8 100644 --- a/docs/tutorial/collation.txt +++ b/docs/tutorial/collation.txt @@ -206,7 +206,7 @@ specify a collation. $collection = (new MongoDB\Client)->test->names; $document = $collection->findOneAndUpdate( - ['first_name' => ['$lt' =-> 'Gunter']], + ['first_name' => ['$lt' => 'Gunter']], ['$set' => ['verified' => true]] ); @@ -231,7 +231,7 @@ specified, which uses the locale ``de@collation=phonebook``. $collection = (new MongoDB\Client)->test->names; $document = $collection->findOneAndUpdate( - ['first_name' => ['$lt' =-> 'Gunter']], + ['first_name' => ['$lt' => 'Gunter']], ['$set' => ['verified' => true]], [ 'collation' => ['locale' => 'de@collation=phonebook'], From 27f664895815335a6f95083329973f7f167f279e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 13 Aug 2021 13:13:09 +0200 Subject: [PATCH 077/321] Add #[ReturnTypeWillChange] and related `@return` (#855) --- src/ChangeStream.php | 6 ++++++ src/MapReduceResult.php | 2 ++ src/Model/BSONArray.php | 2 ++ src/Model/BSONDocument.php | 2 ++ src/Model/BSONIterator.php | 6 ++++++ src/Model/CachingIterator.php | 7 +++++++ src/Model/CallbackIterator.php | 6 ++++++ src/Model/ChangeStreamIterator.php | 6 ++++++ src/Model/CollectionInfo.php | 7 +++++++ src/Model/CollectionInfoIterator.php | 2 ++ src/Model/DatabaseInfo.php | 7 +++++++ src/Model/DatabaseInfoIterator.php | 2 ++ src/Model/DatabaseInfoLegacyIterator.php | 8 ++++++++ src/Model/IndexInfo.php | 7 +++++++ src/Model/IndexInfoIterator.php | 2 ++ tests/UnifiedSpecTests/EntityMap.php | 5 ++++- tests/UnifiedSpecTests/UnifiedTestCase.php | 3 ++- 17 files changed, 78 insertions(+), 2 deletions(-) diff --git a/src/ChangeStream.php b/src/ChangeStream.php index 627dae304..db46e3518 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -24,6 +24,7 @@ use MongoDB\Driver\Exception\ServerException; use MongoDB\Exception\ResumeTokenException; use MongoDB\Model\ChangeStreamIterator; +use ReturnTypeWillChange; use function call_user_func; use function in_array; @@ -102,6 +103,7 @@ public function __construct(ChangeStreamIterator $iterator, callable $resumeCall * @see http://php.net/iterator.current * @return mixed */ + #[ReturnTypeWillChange] public function current() { return $this->iterator->current(); @@ -133,6 +135,7 @@ public function getResumeToken() * @see http://php.net/iterator.key * @return mixed */ + #[ReturnTypeWillChange] public function key() { if ($this->valid()) { @@ -147,6 +150,7 @@ public function key() * @return void * @throws ResumeTokenException */ + #[ReturnTypeWillChange] public function next() { try { @@ -162,6 +166,7 @@ public function next() * @return void * @throws ResumeTokenException */ + #[ReturnTypeWillChange] public function rewind() { try { @@ -179,6 +184,7 @@ public function rewind() * @see http://php.net/iterator.valid * @return boolean */ + #[ReturnTypeWillChange] public function valid() { return $this->iterator->valid(); diff --git a/src/MapReduceResult.php b/src/MapReduceResult.php index e4e862293..24b102965 100644 --- a/src/MapReduceResult.php +++ b/src/MapReduceResult.php @@ -18,6 +18,7 @@ namespace MongoDB; use IteratorAggregate; +use ReturnTypeWillChange; use stdClass; use Traversable; @@ -87,6 +88,7 @@ public function getExecutionTimeMS() * @see http://php.net/iteratoraggregate.getiterator * @return Traversable */ + #[ReturnTypeWillChange] public function getIterator() { return call_user_func($this->getIterator); diff --git a/src/Model/BSONArray.php b/src/Model/BSONArray.php index bdcb240b4..3594d80ad 100644 --- a/src/Model/BSONArray.php +++ b/src/Model/BSONArray.php @@ -21,6 +21,7 @@ use JsonSerializable; use MongoDB\BSON\Serializable; use MongoDB\BSON\Unserializable; +use ReturnTypeWillChange; use function array_values; use function MongoDB\recursive_copy; @@ -95,6 +96,7 @@ public function bsonUnserialize(array $data) * @see http://php.net/jsonserializable.jsonserialize * @return array */ + #[ReturnTypeWillChange] public function jsonSerialize() { return array_values($this->getArrayCopy()); diff --git a/src/Model/BSONDocument.php b/src/Model/BSONDocument.php index f6381d5cf..901ee179d 100644 --- a/src/Model/BSONDocument.php +++ b/src/Model/BSONDocument.php @@ -21,6 +21,7 @@ use JsonSerializable; use MongoDB\BSON\Serializable; use MongoDB\BSON\Unserializable; +use ReturnTypeWillChange; use function MongoDB\recursive_copy; @@ -102,6 +103,7 @@ public function bsonUnserialize(array $data) * @see http://php.net/jsonserializable.jsonserialize * @return object */ + #[ReturnTypeWillChange] public function jsonSerialize() { return (object) $this->getArrayCopy(); diff --git a/src/Model/BSONIterator.php b/src/Model/BSONIterator.php index 761984efa..65a7f8c93 100644 --- a/src/Model/BSONIterator.php +++ b/src/Model/BSONIterator.php @@ -20,6 +20,7 @@ use Iterator; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnexpectedValueException; +use ReturnTypeWillChange; use function is_array; use function MongoDB\BSON\toPHP; @@ -86,6 +87,7 @@ public function __construct($data, array $options = []) * @see http://php.net/iterator.current * @return mixed */ + #[ReturnTypeWillChange] public function current() { return $this->current; @@ -95,6 +97,7 @@ public function current() * @see http://php.net/iterator.key * @return mixed */ + #[ReturnTypeWillChange] public function key() { return $this->key; @@ -104,6 +107,7 @@ public function key() * @see http://php.net/iterator.next * @return void */ + #[ReturnTypeWillChange] public function next() { $this->key++; @@ -115,6 +119,7 @@ public function next() * @see http://php.net/iterator.rewind * @return void */ + #[ReturnTypeWillChange] public function rewind() { $this->key = 0; @@ -127,6 +132,7 @@ public function rewind() * @see http://php.net/iterator.valid * @return boolean */ + #[ReturnTypeWillChange] public function valid() { return $this->current !== null; diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index 9898aefab..4a5edf10f 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -20,6 +20,7 @@ use Countable; use Iterator; use IteratorIterator; +use ReturnTypeWillChange; use Traversable; use function count; @@ -71,6 +72,7 @@ public function __construct(Traversable $traversable) * @see http://php.net/countable.count * @return integer */ + #[ReturnTypeWillChange] public function count() { $this->exhaustIterator(); @@ -82,6 +84,7 @@ public function count() * @see http://php.net/iterator.current * @return mixed */ + #[ReturnTypeWillChange] public function current() { return current($this->items); @@ -91,6 +94,7 @@ public function current() * @see http://php.net/iterator.key * @return mixed */ + #[ReturnTypeWillChange] public function key() { return key($this->items); @@ -100,6 +104,7 @@ public function key() * @see http://php.net/iterator.next * @return void */ + #[ReturnTypeWillChange] public function next() { if (! $this->iteratorExhausted) { @@ -118,6 +123,7 @@ public function next() * @see http://php.net/iterator.rewind * @return void */ + #[ReturnTypeWillChange] public function rewind() { /* If the iterator has advanced, exhaust it now so that future iteration @@ -134,6 +140,7 @@ public function rewind() * @see http://php.net/iterator.valid * @return boolean */ + #[ReturnTypeWillChange] public function valid() { return $this->key() !== null; diff --git a/src/Model/CallbackIterator.php b/src/Model/CallbackIterator.php index 82afa925e..0029b33a0 100644 --- a/src/Model/CallbackIterator.php +++ b/src/Model/CallbackIterator.php @@ -20,6 +20,7 @@ use Closure; use Iterator; use IteratorIterator; +use ReturnTypeWillChange; use Traversable; /** @@ -45,6 +46,7 @@ public function __construct(Traversable $traversable, Closure $callback) * @see http://php.net/iterator.current * @return mixed */ + #[ReturnTypeWillChange] public function current() { return ($this->callback)($this->iterator->current()); @@ -54,6 +56,7 @@ public function current() * @see http://php.net/iterator.key * @return mixed */ + #[ReturnTypeWillChange] public function key() { return $this->iterator->key(); @@ -63,6 +66,7 @@ public function key() * @see http://php.net/iterator.next * @return void */ + #[ReturnTypeWillChange] public function next() { $this->iterator->next(); @@ -72,6 +76,7 @@ public function next() * @see http://php.net/iterator.rewind * @return void */ + #[ReturnTypeWillChange] public function rewind() { $this->iterator->rewind(); @@ -81,6 +86,7 @@ public function rewind() * @see http://php.net/iterator.valid * @return boolean */ + #[ReturnTypeWillChange] public function valid() { return $this->iterator->valid(); diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index 76952c789..69f5e4c8b 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -28,6 +28,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\ResumeTokenException; use MongoDB\Exception\UnexpectedValueException; +use ReturnTypeWillChange; use function count; use function is_array; @@ -139,6 +140,7 @@ final public function commandSucceeded(CommandSucceededEvent $event) * @see https://php.net/iteratoriterator.current * @return mixed */ + #[ReturnTypeWillChange] public function current() { return $this->isValid ? parent::current() : null; @@ -170,6 +172,7 @@ public function getServer(): Server * @see https://php.net/iteratoriterator.key * @return mixed */ + #[ReturnTypeWillChange] public function key() { return $this->isValid ? parent::key() : null; @@ -179,6 +182,7 @@ public function key() * @see https://php.net/iteratoriterator.rewind * @return void */ + #[ReturnTypeWillChange] public function next() { /* Determine if advancing the iterator will execute a getMore command @@ -206,6 +210,7 @@ public function next() * @see https://php.net/iteratoriterator.rewind * @return void */ + #[ReturnTypeWillChange] public function rewind() { if ($this->isRewindNop) { @@ -220,6 +225,7 @@ public function rewind() * @see https://php.net/iteratoriterator.valid * @return boolean */ + #[ReturnTypeWillChange] public function valid() { return $this->isValid; diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php index 63d135de6..cd4025a0a 100644 --- a/src/Model/CollectionInfo.php +++ b/src/Model/CollectionInfo.php @@ -19,6 +19,7 @@ use ArrayAccess; use MongoDB\Exception\BadMethodCallException; +use ReturnTypeWillChange; use function array_key_exists; @@ -156,6 +157,7 @@ public function isCapped() * @param mixed $key * @return boolean */ + #[ReturnTypeWillChange] public function offsetExists($key) { return array_key_exists($key, $this->info); @@ -168,6 +170,7 @@ public function offsetExists($key) * @param mixed $key * @return mixed */ + #[ReturnTypeWillChange] public function offsetGet($key) { return $this->info[$key]; @@ -180,7 +183,9 @@ public function offsetGet($key) * @param mixed $key * @param mixed $value * @throws BadMethodCallException + * @return void */ + #[ReturnTypeWillChange] public function offsetSet($key, $value) { throw BadMethodCallException::classIsImmutable(self::class); @@ -192,7 +197,9 @@ public function offsetSet($key, $value) * @see http://php.net/arrayaccess.offsetunset * @param mixed $key * @throws BadMethodCallException + * @return void */ + #[ReturnTypeWillChange] public function offsetUnset($key) { throw BadMethodCallException::classIsImmutable(self::class); diff --git a/src/Model/CollectionInfoIterator.php b/src/Model/CollectionInfoIterator.php index 999ee9aec..8609c977a 100644 --- a/src/Model/CollectionInfoIterator.php +++ b/src/Model/CollectionInfoIterator.php @@ -18,6 +18,7 @@ namespace MongoDB\Model; use Iterator; +use ReturnTypeWillChange; /** * CollectionInfoIterator interface. @@ -34,5 +35,6 @@ interface CollectionInfoIterator extends Iterator * * @return CollectionInfo */ + #[ReturnTypeWillChange] public function current(); } diff --git a/src/Model/DatabaseInfo.php b/src/Model/DatabaseInfo.php index 40e377fc0..d42b01d31 100644 --- a/src/Model/DatabaseInfo.php +++ b/src/Model/DatabaseInfo.php @@ -19,6 +19,7 @@ use ArrayAccess; use MongoDB\Exception\BadMethodCallException; +use ReturnTypeWillChange; use function array_key_exists; @@ -94,6 +95,7 @@ public function isEmpty() * @param mixed $key * @return boolean */ + #[ReturnTypeWillChange] public function offsetExists($key) { return array_key_exists($key, $this->info); @@ -106,6 +108,7 @@ public function offsetExists($key) * @param mixed $key * @return mixed */ + #[ReturnTypeWillChange] public function offsetGet($key) { return $this->info[$key]; @@ -118,7 +121,9 @@ public function offsetGet($key) * @param mixed $key * @param mixed $value * @throws BadMethodCallException + * @return void */ + #[ReturnTypeWillChange] public function offsetSet($key, $value) { throw BadMethodCallException::classIsImmutable(self::class); @@ -130,7 +135,9 @@ public function offsetSet($key, $value) * @see http://php.net/arrayaccess.offsetunset * @param mixed $key * @throws BadMethodCallException + * @return void */ + #[ReturnTypeWillChange] public function offsetUnset($key) { throw BadMethodCallException::classIsImmutable(self::class); diff --git a/src/Model/DatabaseInfoIterator.php b/src/Model/DatabaseInfoIterator.php index 91576eb1b..78609712c 100644 --- a/src/Model/DatabaseInfoIterator.php +++ b/src/Model/DatabaseInfoIterator.php @@ -18,6 +18,7 @@ namespace MongoDB\Model; use Iterator; +use ReturnTypeWillChange; /** * DatabaseInfoIterator interface. @@ -34,5 +35,6 @@ interface DatabaseInfoIterator extends Iterator * * @return DatabaseInfo */ + #[ReturnTypeWillChange] public function current(); } diff --git a/src/Model/DatabaseInfoLegacyIterator.php b/src/Model/DatabaseInfoLegacyIterator.php index e50b54166..8acd87a17 100644 --- a/src/Model/DatabaseInfoLegacyIterator.php +++ b/src/Model/DatabaseInfoLegacyIterator.php @@ -17,6 +17,8 @@ namespace MongoDB\Model; +use ReturnTypeWillChange; + use function current; use function key; use function next; @@ -63,6 +65,7 @@ public function current() * @see http://php.net/iterator.key * @return integer */ + #[ReturnTypeWillChange] public function key() { return key($this->databases); @@ -72,7 +75,9 @@ public function key() * Move forward to next element. * * @see http://php.net/iterator.next + * @return void */ + #[ReturnTypeWillChange] public function next() { next($this->databases); @@ -82,7 +87,9 @@ public function next() * Rewind the Iterator to the first element. * * @see http://php.net/iterator.rewind + * @return void */ + #[ReturnTypeWillChange] public function rewind() { reset($this->databases); @@ -94,6 +101,7 @@ public function rewind() * @see http://php.net/iterator.valid * @return boolean */ + #[ReturnTypeWillChange] public function valid() { return key($this->databases) !== null; diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php index dcce520c2..6b6f31722 100644 --- a/src/Model/IndexInfo.php +++ b/src/Model/IndexInfo.php @@ -19,6 +19,7 @@ use ArrayAccess; use MongoDB\Exception\BadMethodCallException; +use ReturnTypeWillChange; use function array_key_exists; use function array_search; @@ -182,6 +183,7 @@ public function isUnique() * @param mixed $key * @return boolean */ + #[ReturnTypeWillChange] public function offsetExists($key) { return array_key_exists($key, $this->info); @@ -199,6 +201,7 @@ public function offsetExists($key) * @param mixed $key * @return mixed */ + #[ReturnTypeWillChange] public function offsetGet($key) { return $this->info[$key]; @@ -211,7 +214,9 @@ public function offsetGet($key) * @param mixed $key * @param mixed $value * @throws BadMethodCallException + * @return void */ + #[ReturnTypeWillChange] public function offsetSet($key, $value) { throw BadMethodCallException::classIsImmutable(self::class); @@ -223,7 +228,9 @@ public function offsetSet($key, $value) * @see http://php.net/arrayaccess.offsetunset * @param mixed $key * @throws BadMethodCallException + * @return void */ + #[ReturnTypeWillChange] public function offsetUnset($key) { throw BadMethodCallException::classIsImmutable(self::class); diff --git a/src/Model/IndexInfoIterator.php b/src/Model/IndexInfoIterator.php index 5195172c4..832cb3f46 100644 --- a/src/Model/IndexInfoIterator.php +++ b/src/Model/IndexInfoIterator.php @@ -18,6 +18,7 @@ namespace MongoDB\Model; use Iterator; +use ReturnTypeWillChange; /** * IndexInfoIterator interface. @@ -34,5 +35,6 @@ interface IndexInfoIterator extends Iterator * * @return IndexInfo */ + #[ReturnTypeWillChange] public function current(); } diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php index 28be168fe..9499130d4 100644 --- a/tests/UnifiedSpecTests/EntityMap.php +++ b/tests/UnifiedSpecTests/EntityMap.php @@ -13,6 +13,7 @@ use MongoDB\Tests\UnifiedSpecTests\Constraint\IsBsonType; use PHPUnit\Framework\Assert; use PHPUnit\Framework\Constraint\Constraint; +use ReturnTypeWillChange; use stdClass; use function array_key_exists; @@ -58,7 +59,7 @@ public function __destruct() /** * @see http://php.net/arrayaccess.offsetexists */ - public function offsetExists($id) + public function offsetExists($id): bool { assertIsString($id); @@ -67,7 +68,9 @@ public function offsetExists($id) /** * @see http://php.net/arrayaccess.offsetget + * @return mixed */ + #[ReturnTypeWillChange] public function offsetGet($id) { assertIsString($id); diff --git a/tests/UnifiedSpecTests/UnifiedTestCase.php b/tests/UnifiedSpecTests/UnifiedTestCase.php index d3007f0cf..e98db65c0 100644 --- a/tests/UnifiedSpecTests/UnifiedTestCase.php +++ b/tests/UnifiedSpecTests/UnifiedTestCase.php @@ -5,6 +5,7 @@ use Generator; use IteratorAggregate; use stdClass; +use Traversable; use function file_get_contents; use function MongoDB\BSON\fromJSON; @@ -57,7 +58,7 @@ private function __construct(stdClass $test, string $schemaVersion, ?array $runO * @see https://www.php.net/manual/en/iteratoraggregate.getiterator.php * @see https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list */ - public function getIterator() + public function getIterator(): Traversable { yield $this->test; yield $this->schemaVersion; From 4a14c76e7c52ca9efef65bf1c80d9fe598c35d31 Mon Sep 17 00:00:00 2001 From: Alexander Golin Date: Tue, 17 Aug 2021 16:38:39 -0400 Subject: [PATCH 078/321] PHPLIB-692: Standardize copyright formatting (#856) --- src/BulkWriteResult.php | 2 +- src/ChangeStream.php | 2 +- src/Client.php | 2 +- src/Collection.php | 2 +- src/Database.php | 2 +- src/DeleteResult.php | 2 +- src/Exception/BadMethodCallException.php | 2 +- src/Exception/Exception.php | 2 +- src/Exception/InvalidArgumentException.php | 2 +- src/Exception/ResumeTokenException.php | 2 +- src/Exception/RuntimeException.php | 2 +- src/Exception/UnexpectedValueException.php | 2 +- src/Exception/UnsupportedException.php | 2 +- src/GridFS/Bucket.php | 2 +- src/GridFS/CollectionWrapper.php | 2 +- src/GridFS/Exception/CorruptFileException.php | 2 +- src/GridFS/Exception/FileNotFoundException.php | 2 +- src/GridFS/ReadableStream.php | 2 +- src/GridFS/StreamWrapper.php | 2 +- src/GridFS/WritableStream.php | 2 +- src/InsertManyResult.php | 2 +- src/InsertOneResult.php | 2 +- src/MapReduceResult.php | 2 +- src/Model/BSONIterator.php | 2 +- src/Model/CachingIterator.php | 2 +- src/Model/CallbackIterator.php | 2 +- src/Model/ChangeStreamIterator.php | 2 +- src/Model/CollectionInfo.php | 2 +- src/Model/CollectionInfoCommandIterator.php | 2 +- src/Model/CollectionInfoIterator.php | 2 +- src/Model/DatabaseInfo.php | 2 +- src/Model/DatabaseInfoIterator.php | 2 +- src/Model/DatabaseInfoLegacyIterator.php | 2 +- src/Model/IndexInfo.php | 2 +- src/Model/IndexInfoIterator.php | 2 +- src/Model/IndexInfoIteratorIterator.php | 2 +- src/Model/IndexInput.php | 2 +- src/Operation/Aggregate.php | 2 +- src/Operation/BulkWrite.php | 2 +- src/Operation/Count.php | 2 +- src/Operation/CountDocuments.php | 2 +- src/Operation/CreateCollection.php | 2 +- src/Operation/CreateIndexes.php | 2 +- src/Operation/DatabaseCommand.php | 2 +- src/Operation/Delete.php | 2 +- src/Operation/DeleteMany.php | 2 +- src/Operation/DeleteOne.php | 2 +- src/Operation/Distinct.php | 2 +- src/Operation/DropCollection.php | 2 +- src/Operation/DropDatabase.php | 2 +- src/Operation/DropIndexes.php | 2 +- src/Operation/EstimatedDocumentCount.php | 2 +- src/Operation/Executable.php | 2 +- src/Operation/Explain.php | 2 +- src/Operation/Explainable.php | 2 +- src/Operation/Find.php | 2 +- src/Operation/FindAndModify.php | 2 +- src/Operation/FindOne.php | 2 +- src/Operation/FindOneAndDelete.php | 2 +- src/Operation/FindOneAndReplace.php | 2 +- src/Operation/FindOneAndUpdate.php | 2 +- src/Operation/InsertMany.php | 2 +- src/Operation/InsertOne.php | 2 +- src/Operation/ListCollections.php | 2 +- src/Operation/ListDatabases.php | 2 +- src/Operation/ListIndexes.php | 2 +- src/Operation/MapReduce.php | 2 +- src/Operation/ModifyCollection.php | 2 +- src/Operation/ReplaceOne.php | 2 +- src/Operation/Update.php | 2 +- src/Operation/UpdateMany.php | 2 +- src/Operation/UpdateOne.php | 2 +- src/Operation/Watch.php | 2 +- src/UpdateResult.php | 2 +- src/functions.php | 2 +- 75 files changed, 75 insertions(+), 75 deletions(-) diff --git a/src/BulkWriteResult.php b/src/BulkWriteResult.php index 68af2cd75..ad0a57c06 100644 --- a/src/BulkWriteResult.php +++ b/src/BulkWriteResult.php @@ -1,6 +1,6 @@ Date: Fri, 20 Aug 2021 17:13:01 -0400 Subject: [PATCH 079/321] PHPLIB-707: Remove modifiers from command monitoring spec test (#857) Synced with mongodb/specifications@b8928fa15752a9270e39ad2d2a14fd0b3eb0bfbc --- tests/SpecTests/command-monitoring/find.json | 28 +++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/tests/SpecTests/command-monitoring/find.json b/tests/SpecTests/command-monitoring/find.json index 55b185cc5..e2bb95306 100644 --- a/tests/SpecTests/command-monitoring/find.json +++ b/tests/SpecTests/command-monitoring/find.json @@ -89,21 +89,19 @@ "skip": { "$numberLong": "2" }, - "modifiers": { - "$comment": "test", - "$hint": { - "_id": 1 - }, - "$max": { - "_id": 6 - }, - "$maxTimeMS": 6000, - "$min": { - "_id": 0 - }, - "$returnKey": false, - "$showDiskLoc": false - } + "comment": "test", + "hint": { + "_id": 1 + }, + "max": { + "_id": 6 + }, + "maxTimeMS": 6000, + "min": { + "_id": 0 + }, + "returnKey": false, + "showRecordId": false } }, "expectations": [ From 702dacb75e79b7349cb9905eab1dc962231f2dfe Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 30 Aug 2021 13:08:06 -0400 Subject: [PATCH 080/321] PHPLIB-713: Document hint option for findOneAndDelete --- ...MongoDBCollection-method-findOneAndDelete-option.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml index 520b4de19..894b51b82 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml @@ -10,6 +10,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: hint +post: | + This option is available in MongoDB 4.4+ and will result in an exception at + execution time if specified for an older server version. + + .. versionadded:: 1.7 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS From 57cd7e0b261c34ed63a1c7bad4c28ee46d3d414d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 30 Aug 2021 14:06:46 -0400 Subject: [PATCH 081/321] PHPLIB-708: Sync unified test runner valid-fail tests (#858) Synced with mongodb/specifications@73d1286c4fd34a71583feb262c0105b4286cb295 --- .../entity-findCursor-malformed.json | 44 +++++++++++++++++ ...ind-cursor.json => entity-findCursor.json} | 12 +---- .../ignoreResultAndError-malformed.json | 48 +++++++++++++++++++ .../valid-fail/ignoreResultAndError.json | 13 ----- 4 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 tests/UnifiedSpecTests/valid-fail/entity-findCursor-malformed.json rename tests/UnifiedSpecTests/valid-fail/{entity-find-cursor.json => entity-findCursor.json} (76%) create mode 100644 tests/UnifiedSpecTests/valid-fail/ignoreResultAndError-malformed.json diff --git a/tests/UnifiedSpecTests/valid-fail/entity-findCursor-malformed.json b/tests/UnifiedSpecTests/valid-fail/entity-findCursor-malformed.json new file mode 100644 index 000000000..0956efa4c --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/entity-findCursor-malformed.json @@ -0,0 +1,44 @@ +{ + "description": "entity-findCursor-malformed", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "databaseName": "database0Name", + "collectionName": "coll0", + "documents": [] + } + ], + "tests": [ + { + "description": "createFindCursor fails if filter is not specified", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "saveResultAsEntity": "cursor0" + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json b/tests/UnifiedSpecTests/valid-fail/entity-findCursor.json similarity index 76% rename from tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json rename to tests/UnifiedSpecTests/valid-fail/entity-findCursor.json index f4c5bcdf4..389e448c0 100644 --- a/tests/UnifiedSpecTests/valid-fail/entity-find-cursor.json +++ b/tests/UnifiedSpecTests/valid-fail/entity-findCursor.json @@ -1,5 +1,5 @@ { - "description": "entity-find-cursor", + "description": "entity-findCursor", "schemaVersion": "1.3", "createEntities": [ { @@ -30,16 +30,6 @@ } ], "tests": [ - { - "description": "createFindCursor fails if filter is not specified", - "operations": [ - { - "name": "createFindCursor", - "object": "collection0", - "saveResultAsEntity": "cursor0" - } - ] - }, { "description": "iterateUntilDocumentOrError fails if it references a nonexistent entity", "operations": [ diff --git a/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError-malformed.json b/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError-malformed.json new file mode 100644 index 000000000..b64779c72 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError-malformed.json @@ -0,0 +1,48 @@ +{ + "description": "ignoreResultAndError-malformed", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "malformed operation fails if ignoreResultAndError is true", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "foo": "bar" + }, + "ignoreResultAndError": true + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json b/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json index 4457040b4..01b2421a9 100644 --- a/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json +++ b/tests/UnifiedSpecTests/valid-fail/ignoreResultAndError.json @@ -54,19 +54,6 @@ "ignoreResultAndError": false } ] - }, - { - "description": "malformed operation fails if ignoreResultAndError is true", - "operations": [ - { - "name": "insertOne", - "object": "collection0", - "arguments": { - "foo": "bar" - }, - "ignoreResultAndError": true - } - ] } ] } From e7874759d0703fbe8dda1b606a4fccbf27db0b67 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 31 Aug 2021 11:11:53 -0400 Subject: [PATCH 082/321] PHPLIB-712: Allow hint for unacknowledged writes using OP_MSG when supported by the server (#859) * Sync unified CRUD spec tests Synced with mongodb/specifications@59a5dadb2eeab8bba5a7d9a9acd47aa8c1d594cf Note: aggregate tests are intentionally excluded since those will be synced by mongodb/mongo-php-library#854 * PHPLIB-711: Unwrap BulkWriteException when evaluating isClientError * Client-side errors for hint with update, delete, and findAndModify The CRUD spec requires a client-side error if hint is used and the server would not otherwise raise an error for an unsupported option. This was already being done, but this commit renames an internal constant and adds functional tests. A client-side error is also required if hint is used with an unacknowledged write concern and the server does not support hint for the operation (regardless of error reporting for unsupported options). This was previously done only for FindAndModify; however, it failed to detect some acknowledged write concerns (PHPLIB-712). That issue has been fixed and the commit additionally adds this behavior for update and delete operations. --- src/Operation/Delete.php | 22 +- src/Operation/FindAndModify.php | 36 +-- src/Operation/Update.php | 22 +- src/functions.php | 20 ++ tests/FunctionsTest.php | 29 ++ tests/Operation/DeleteFunctionalTest.php | 41 +++ .../Operation/FindAndModifyFunctionalTest.php | 38 +++ tests/Operation/UpdateFunctionalTest.php | 41 +++ tests/UnifiedSpecTests/ExpectedError.php | 21 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 22 -- ...kWrite-deleteMany-hint-unacknowledged.json | 269 +++++++++++++++ ...lkWrite-deleteOne-hint-unacknowledged.json | 265 +++++++++++++++ ...kWrite-replaceOne-hint-unacknowledged.json | 293 +++++++++++++++++ ...kWrite-updateMany-hint-unacknowledged.json | 305 ++++++++++++++++++ ...lkWrite-updateOne-hint-unacknowledged.json | 305 ++++++++++++++++++ .../crud/deleteMany-hint-unacknowledged.json | 245 ++++++++++++++ .../crud/deleteOne-hint-unacknowledged.json | 241 ++++++++++++++ .../findOneAndDelete-hint-unacknowledged.json | 225 +++++++++++++ ...findOneAndReplace-hint-unacknowledged.json | 248 ++++++++++++++ .../findOneAndUpdate-hint-unacknowledged.json | 253 +++++++++++++++ .../crud/replaceOne-hint-unacknowledged.json | 269 +++++++++++++++ ...ged-bulkWrite-delete-hint-clientError.json | 193 ----------- ...ged-bulkWrite-update-hint-clientError.json | 284 ---------------- ...nowledged-deleteMany-hint-clientError.json | 149 --------- ...knowledged-deleteOne-hint-clientError.json | 133 -------- ...ged-findOneAndDelete-hint-clientError.json | 133 -------- ...ed-findOneAndReplace-hint-clientError.json | 139 -------- ...ged-findOneAndUpdate-hint-clientError.json | 143 -------- ...nowledged-replaceOne-hint-clientError.json | 143 -------- ...nowledged-updateMany-hint-clientError.json | 159 --------- ...knowledged-updateOne-hint-clientError.json | 147 --------- .../crud/updateMany-hint-unacknowledged.json | 281 ++++++++++++++++ .../crud/updateOne-hint-unacknowledged.json | 281 ++++++++++++++++ 33 files changed, 3713 insertions(+), 1682 deletions(-) create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-updateMany-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-updateOne-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/deleteMany-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndDelete-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/replaceOne-hint-unacknowledged.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json delete mode 100644 tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json create mode 100644 tests/UnifiedSpecTests/crud/updateMany-hint-unacknowledged.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-hint-unacknowledged.json diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 1d7d393a3..cf2f45edc 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -29,6 +29,7 @@ use function is_array; use function is_object; use function is_string; +use function MongoDB\is_write_concern_acknowledged; use function MongoDB\server_supports_feature; /** @@ -45,8 +46,11 @@ class Delete implements Executable, Explainable /** @var integer */ private static $wireVersionForCollation = 5; + /** @var integer */ + private static $wireVersionForHint = 9; + /** @var int */ - private static $wireVersionForHintServerSideError = 5; + private static $wireVersionForUnsupportedOptionServerSideError = 5; /** @var string */ private $databaseName; @@ -146,10 +150,18 @@ public function execute(Server $server) throw UnsupportedException::collationNotSupported(); } - /* Server versions >= 3.4.0 raise errors for unknown update - * options. For previous versions, the CRUD spec requires a client-side - * error. */ - if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHintServerSideError)) { + /* Server versions >= 3.4.0 raise errors for unsupported update options. + * For previous versions, the CRUD spec requires a client-side error. */ + if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) { + throw UnsupportedException::hintNotSupported(); + } + + /* CRUD spec requires a client-side error when using "hint" with an + * unacknowledged write concern on an unsupported server. */ + if ( + isset($this->options['writeConcern']) && ! is_write_concern_acknowledged($this->options['writeConcern']) && + isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHint) + ) { throw UnsupportedException::hintNotSupported(); } diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 6416f73d6..27cf68618 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -34,6 +34,7 @@ use function is_string; use function MongoDB\create_field_path_type_map; use function MongoDB\is_pipeline; +use function MongoDB\is_write_concern_acknowledged; use function MongoDB\server_supports_feature; /** @@ -60,7 +61,7 @@ class FindAndModify implements Executable, Explainable private static $wireVersionForHint = 9; /** @var integer */ - private static $wireVersionForHintServerSideError = 8; + private static $wireVersionForUnsupportedOptionServerSideError = 8; /** @var integer */ private static $wireVersionForWriteConcern = 4; @@ -245,11 +246,18 @@ public function execute(Server $server) throw UnsupportedException::collationNotSupported(); } - /* Server versions >= 4.1.10 raise errors for unknown findAndModify - * options (SERVER-40005), but the CRUD spec requires client-side errors - * for server versions < 4.2. For later versions, we'll rely on the - * server to either utilize the option or report its own error. */ - if (isset($this->options['hint']) && ! $this->isHintSupported($server)) { + /* Server versions >= 4.2.0 raise errors for unsupported update options. + * For previous versions, the CRUD spec requires a client-side error. */ + if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) { + throw UnsupportedException::hintNotSupported(); + } + + /* CRUD spec requires a client-side error when using "hint" with an + * unacknowledged write concern on an unsupported server. */ + if ( + isset($this->options['writeConcern']) && ! is_write_concern_acknowledged($this->options['writeConcern']) && + isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHint) + ) { throw UnsupportedException::hintNotSupported(); } @@ -350,20 +358,4 @@ private function createOptions() return $options; } - - private function isAcknowledgedWriteConcern(): bool - { - if (! isset($this->options['writeConcern'])) { - return true; - } - - return $this->options['writeConcern']->getW() > 1 || $this->options['writeConcern']->getJournal(); - } - - private function isHintSupported(Server $server): bool - { - $requiredWireVersion = $this->isAcknowledgedWriteConcern() ? self::$wireVersionForHintServerSideError : self::$wireVersionForHint; - - return server_supports_feature($server, $requiredWireVersion); - } } diff --git a/src/Operation/Update.php b/src/Operation/Update.php index bc2f4243b..52164db17 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -32,6 +32,7 @@ use function is_string; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; +use function MongoDB\is_write_concern_acknowledged; use function MongoDB\server_supports_feature; /** @@ -55,7 +56,10 @@ class Update implements Executable, Explainable private static $wireVersionForDocumentLevelValidation = 4; /** @var integer */ - private static $wireVersionForHintServerSideError = 5; + private static $wireVersionForHint = 8; + + /** @var integer */ + private static $wireVersionForUnsupportedOptionServerSideError = 5; /** @var string */ private $databaseName; @@ -203,10 +207,18 @@ public function execute(Server $server) throw UnsupportedException::collationNotSupported(); } - /* Server versions >= 3.4.0 raise errors for unknown update - * options. For previous versions, the CRUD spec requires a client-side - * error. */ - if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHintServerSideError)) { + /* Server versions >= 3.4.0 raise errors for unsupported update options. + * For previous versions, the CRUD spec requires a client-side error. */ + if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) { + throw UnsupportedException::hintNotSupported(); + } + + /* CRUD spec requires a client-side error when using "hint" with an + * unacknowledged write concern on an unsupported server. */ + if ( + isset($this->options['writeConcern']) && ! is_write_concern_acknowledged($this->options['writeConcern']) && + isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHint) + ) { throw UnsupportedException::hintNotSupported(); } diff --git a/src/functions.php b/src/functions.php index 58b1a30c2..141c0b006 100644 --- a/src/functions.php +++ b/src/functions.php @@ -23,6 +23,7 @@ use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; use MongoDB\Driver\Session; +use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\RuntimeException; use MongoDB\Operation\WithTransaction; @@ -239,6 +240,25 @@ function is_mapreduce_output_inline($out): bool return key($out) === 'inline'; } +/** + * Return whether the write concern is acknowledged. + * + * This function is similar to mongoc_write_concern_is_acknowledged but does not + * check the fsync option since that was never supported in the PHP driver. + * + * @internal + * @see https://docs.mongodb.com/manual/reference/write-concern/ + * @param WriteConcern $writeConcern + * @return boolean + */ +function is_write_concern_acknowledged(WriteConcern $writeConcern): bool +{ + /* Note: -1 corresponds to MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED, which is + * deprecated synonym of MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED and slated + * for removal in libmongoc 2.0. */ + return ($writeConcern->getW() !== 0 && $writeConcern->getW() !== -1) || $writeConcern->getJournal() === true; +} + /** * Return whether the server supports a particular feature. * diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php index 1644ecb73..d3ead4abc 100644 --- a/tests/FunctionsTest.php +++ b/tests/FunctionsTest.php @@ -2,6 +2,7 @@ namespace MongoDB\Tests; +use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Model\BSONArray; use MongoDB\Model\BSONDocument; @@ -12,6 +13,7 @@ use function MongoDB\is_first_key_operator; use function MongoDB\is_mapreduce_output_inline; use function MongoDB\is_pipeline; +use function MongoDB\is_write_concern_acknowledged; /** * Unit tests for utility functions. @@ -255,4 +257,31 @@ public function providePipelines() 'DbRef in numeric field as object' => [false, (object) ['0' => ['$ref' => 'foo', '$id' => 'bar']]], ]; } + + /** + * @dataProvider provideWriteConcerns + */ + public function testIsWriteConcernAcknowledged($expected, WriteConcern $writeConcern): void + { + $this->assertSame($expected, is_write_concern_acknowledged($writeConcern)); + } + + public function provideWriteConcerns(): array + { + // Note: WriteConcern constructor prohibits w=-1 or w=0 and journal=true + return [ + 'MONGOC_WRITE_CONCERN_W_MAJORITY' => [true, new WriteConcern(-3)], + 'MONGOC_WRITE_CONCERN_W_DEFAULT' => [true, new WriteConcern(-2)], + 'MONGOC_WRITE_CONCERN_W_DEFAULT and journal=true' => [true, new WriteConcern(-2, 0, true)], + 'MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED' => [false, new WriteConcern(-1)], + 'MONGOC_WRITE_CONCERN_W_ERRORS_IGNORED and journal=false' => [false, new WriteConcern(-1, 0, false)], + 'MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED' => [false, new WriteConcern(0)], + 'MONGOC_WRITE_CONCERN_W_UNACKNOWLEDGED and journal=false' => [false, new WriteConcern(0, 0, false)], + 'w=1' => [true, new WriteConcern(1)], + 'w=1 and journal=false' => [true, new WriteConcern(1, 0, false)], + 'w=1 and journal=true' => [true, new WriteConcern(1, 0, true)], + 'majority' => [true, new WriteConcern(WriteConcern::MAJORITY)], + 'tag' => [true, new WriteConcern('tag')], + ]; + } } diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php index 9fae16cd2..3b0058ed1 100644 --- a/tests/Operation/DeleteFunctionalTest.php +++ b/tests/Operation/DeleteFunctionalTest.php @@ -7,6 +7,7 @@ use MongoDB\Driver\BulkWrite; use MongoDB\Driver\WriteConcern; use MongoDB\Exception\BadMethodCallException; +use MongoDB\Exception\UnsupportedException; use MongoDB\Operation\Delete; use MongoDB\Tests\CommandObserver; @@ -63,6 +64,46 @@ public function testDeleteMany(): void $this->assertSameDocuments($expected, $this->collection->find()); } + public function testHintOptionUnsupportedClientSideError(): void + { + if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { + $this->markTestSkipped('server reports error for unsupported delete options'); + } + + $operation = new Delete( + $this->getDatabaseName(), + $this->getCollectionName(), + [], + 0, + ['hint' => '_id_'] + ); + + $this->expectException(UnsupportedException::class); + $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); + + $operation->execute($this->getPrimaryServer()); + } + + public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void + { + if (version_compare($this->getServerVersion(), '4.4.0', '>=')) { + $this->markTestSkipped('hint is supported'); + } + + $operation = new Delete( + $this->getDatabaseName(), + $this->getCollectionName(), + [], + 0, + ['hint' => '_id_', 'writeConcern' => new WriteConcern(0)] + ); + + $this->expectException(UnsupportedException::class); + $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); + + $operation->execute($this->getPrimaryServer()); + } + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index 156632f0e..7d976da40 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -4,6 +4,8 @@ use MongoDB\Driver\BulkWrite; use MongoDB\Driver\ReadPreference; +use MongoDB\Driver\WriteConcern; +use MongoDB\Exception\UnsupportedException; use MongoDB\Model\BSONDocument; use MongoDB\Operation\FindAndModify; use MongoDB\Tests\CommandObserver; @@ -54,6 +56,42 @@ function (array $event): void { ); } + public function testHintOptionUnsupportedClientSideError(): void + { + if (version_compare($this->getServerVersion(), '4.2.0', '>=')) { + $this->markTestSkipped('server reports error for unsupported findAndModify options'); + } + + $operation = new FindAndModify( + $this->getDatabaseName(), + $this->getCollectionName(), + ['remove' => true, 'hint' => '_id_'] + ); + + $this->expectException(UnsupportedException::class); + $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); + + $operation->execute($this->getPrimaryServer()); + } + + public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void + { + if (version_compare($this->getServerVersion(), '4.4.0', '>=')) { + $this->markTestSkipped('hint is supported'); + } + + $operation = new FindAndModify( + $this->getDatabaseName(), + $this->getCollectionName(), + ['remove' => true, 'hint' => '_id_', 'writeConcern' => new WriteConcern(0)] + ); + + $this->expectException(UnsupportedException::class); + $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); + + $operation->execute($this->getPrimaryServer()); + } + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php index 89373400b..c9514e1f2 100644 --- a/tests/Operation/UpdateFunctionalTest.php +++ b/tests/Operation/UpdateFunctionalTest.php @@ -7,6 +7,7 @@ use MongoDB\Driver\BulkWrite; use MongoDB\Driver\WriteConcern; use MongoDB\Exception\BadMethodCallException; +use MongoDB\Exception\UnsupportedException; use MongoDB\Operation\Update; use MongoDB\Tests\CommandObserver; use MongoDB\UpdateResult; @@ -98,6 +99,46 @@ function (array $event): void { ); } + public function testHintOptionUnsupportedClientSideError(): void + { + if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { + $this->markTestSkipped('server reports error for unsupported update options'); + } + + $operation = new Update( + $this->getDatabaseName(), + $this->getCollectionName(), + ['_id' => 1], + ['$inc' => ['x' => 1]], + ['hint' => '_id_'] + ); + + $this->expectException(UnsupportedException::class); + $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); + + $operation->execute($this->getPrimaryServer()); + } + + public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void + { + if (version_compare($this->getServerVersion(), '4.2.0', '>=')) { + $this->markTestSkipped('hint is supported'); + } + + $operation = new Update( + $this->getDatabaseName(), + $this->getCollectionName(), + ['_id' => 1], + ['$inc' => ['x' => 1]], + ['hint' => '_id_', 'writeConcern' => new WriteConcern(0)] + ); + + $this->expectException(UnsupportedException::class); + $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); + + $operation->execute($this->getPrimaryServer()); + } + public function testUpdateOne(): void { $this->createFixtures(3); diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index bcad0d22c..f6e82cd70 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -137,11 +137,7 @@ public function assert(?Throwable $e = null): void assertNotNull($e); if (isset($this->isClientError)) { - if ($this->isClientError) { - assertNotInstanceOf(ServerException::class, $e); - } else { - assertInstanceOf(ServerException::class, $e); - } + $this->assertIsClientError($e); } if (isset($this->messageContains)) { @@ -176,6 +172,21 @@ public function assert(?Throwable $e = null): void } } + private function assertIsClientError(Throwable $e): void + { + /* Note: BulkWriteException may proxy a previous exception. Unwrap it + * to check the original error. */ + if ($e instanceof BulkWriteException && $e->getPrevious() !== null) { + $e = $e->getPrevious(); + } + + if ($this->isClientError) { + assertNotInstanceOf(ServerException::class, $e); + } else { + assertInstanceOf(ServerException::class, $e); + } + } + private function assertCodeName(ServerException $e): void { /* BulkWriteException and ExecutionTimeoutException do not expose diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index fa745979c..ad9d54071 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -21,28 +21,6 @@ class UnifiedSpecTest extends FunctionalTestCase { /** @var array */ private static $incompleteTests = [ - // PHPLIB-573 and DRIVERS-1340 - 'crud/unacknowledged-bulkWrite-delete-hint-clientError: Unacknowledged bulkWrite deleteOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-bulkWrite-delete-hint-clientError: Unacknowledged bulkWrite deleteMany with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite updateOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite updateMany with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-bulkWrite-update-hint-clientError: Unacknowledged bulkWrite replaceOne with hints fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-deleteMany-hint-clientError: Unacknowledged deleteMany with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-deleteMany-hint-clientError: Unacknowledged deleteMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-deleteOne-hint-clientError: Unacknowledged deleteOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-deleteOne-hint-clientError: Unacknowledged deleteOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-findOneAndDelete-hint-clientError: Unacknowledged findOneAndDelete with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-findOneAndDelete-hint-clientError: Unacknowledged findOneAndDelete with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-findOneAndReplace-hint-clientError: Unacknowledged findOneAndReplace with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-findOneAndReplace-hint-clientError: Unacknowledged findOneAndReplace with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-findOneAndUpdate-hint-clientError: Unacknowledged findOneAndUpdate with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-findOneAndUpdate-hint-clientError: Unacknowledged findOneAndUpdate with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-replaceOne-hint-clientError: Unacknowledged ReplaceOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-replaceOne-hint-clientError: Unacknowledged ReplaceOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-updateMany-hint-clientError: Unacknowledged updateMany with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint string fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', - 'crud/unacknowledged-updateOne-hint-clientError: Unacknowledged updateOne with hint document fails with client-side error' => 'PHPLIB-573 and DRIVERS-1340', // PHPC does not implement CMAP 'valid-pass/assertNumberConnectionsCheckedOut: basic assertion succeeds' => 'PHPC does not implement CMAP', 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-hint-unacknowledged.json new file mode 100644 index 000000000..2dda9486e --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-hint-unacknowledged.json @@ -0,0 +1,269 @@ +{ + "description": "bulkWrite-deleteMany-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged deleteMany with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 0 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 0 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-hint-unacknowledged.json new file mode 100644 index 000000000..aadf6d9e9 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-hint-unacknowledged.json @@ -0,0 +1,265 @@ +{ + "description": "bulkWrite-deleteOne-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged deleteOne with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 1 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 1 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-hint-unacknowledged.json new file mode 100644 index 000000000..e54cd704d --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-hint-unacknowledged.json @@ -0,0 +1,293 @@ +{ + "description": "bulkWrite-replaceOne-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged replaceOne with hint string fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged replaceOne with hint document fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged replaceOne with hint string on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "x": 111 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged replaceOne with hint document on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "x": 111 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-hint-unacknowledged.json new file mode 100644 index 000000000..87478918d --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-hint-unacknowledged.json @@ -0,0 +1,305 @@ +{ + "description": "bulkWrite-updateMany-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged updateMany with hint string fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint document fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint string on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint document on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-hint-unacknowledged.json new file mode 100644 index 000000000..1345f6b53 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-hint-unacknowledged.json @@ -0,0 +1,305 @@ +{ + "description": "bulkWrite-updateOne-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged updateOne with hint string fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint document fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint string on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint document on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + } + } + ] + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/deleteMany-hint-unacknowledged.json new file mode 100644 index 000000000..ab7e9c7c0 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteMany-hint-unacknowledged.json @@ -0,0 +1,245 @@ +{ + "description": "deleteMany-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged deleteMany with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 0 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged deleteMany with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 0 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/deleteOne-hint-unacknowledged.json new file mode 100644 index 000000000..1782f0f52 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-hint-unacknowledged.json @@ -0,0 +1,241 @@ +{ + "description": "deleteOne-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged deleteOne with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 1 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged deleteOne with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "deleteOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "limit": 1 + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-unacknowledged.json new file mode 100644 index 000000000..077f9892b --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-hint-unacknowledged.json @@ -0,0 +1,225 @@ +{ + "description": "findOneAndDelete-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged findOneAndDelete with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged findOneAndDelete with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged findOneAndDelete with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": { + "$gt": 1 + } + }, + "remove": true, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged findOneAndDelete with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndDelete", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": { + "$gt": 1 + } + }, + "remove": true, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-unacknowledged.json new file mode 100644 index 000000000..8228d8a2a --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-hint-unacknowledged.json @@ -0,0 +1,248 @@ +{ + "description": "findOneAndReplace-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged findOneAndReplace with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged findOneAndReplace with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged findOneAndReplace with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": { + "$gt": 1 + } + }, + "update": { + "x": 111 + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged findOneAndReplace with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndReplace", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": { + "$gt": 1 + } + }, + "update": { + "x": 111 + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-unacknowledged.json new file mode 100644 index 000000000..d116a06d0 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-hint-unacknowledged.json @@ -0,0 +1,253 @@ +{ + "description": "findOneAndUpdate-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged findOneAndUpdate with hint string fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged findOneAndUpdate with hint document fails with client-side error on pre-4.4 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged findOneAndUpdate with hint string on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged findOneAndUpdate with hint document on 4.4+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "$$type": [ + "string", + "object" + ] + }, + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/replaceOne-hint-unacknowledged.json new file mode 100644 index 000000000..5c5dec64f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/replaceOne-hint-unacknowledged.json @@ -0,0 +1,269 @@ +{ + "description": "replaceOne-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged replaceOne with hint string fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged replaceOne with hint document fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged replaceOne with hint string on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "x": 111 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged replaceOne with hint document on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "replaceOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "replacement": { + "x": 111 + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "x": 111 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json deleted file mode 100644 index dbaa2e84f..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-delete-hint-clientError.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "description": "unacknowledged-bulkWrite-delete-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "BulkWrite_delete_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "BulkWrite_delete_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged bulkWrite deleteOne with hints fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "deleteOne": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - } - }, - { - "deleteOne": { - "filter": { - "_id": 2 - }, - "hint": { - "_id": 1 - } - } - } - ], - "ordered": true - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "BulkWrite_delete_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ] - }, - { - "description": "Unacknowledged bulkWrite deleteMany with hints fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "deleteMany": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "hint": "_id_" - } - }, - { - "deleteMany": { - "filter": { - "_id": { - "$gte": 4 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "ordered": true - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "BulkWrite_delete_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json deleted file mode 100644 index 858967b90..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-bulkWrite-update-hint-clientError.json +++ /dev/null @@ -1,284 +0,0 @@ -{ - "description": "unacknowledged-bulkWrite-update-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "Bulkwrite_update_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "Bulkwrite_update_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged bulkWrite updateOne with hints fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "updateOne": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "updateOne": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "ordered": true - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "Bulkwrite_update_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ] - }, - { - "description": "Unacknowledged bulkWrite updateMany with hints fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "updateMany": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - } - }, - { - "updateMany": { - "filter": { - "_id": { - "$lt": 3 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - } - } - ], - "ordered": true - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "Bulkwrite_update_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ] - }, - { - "description": "Unacknowledged bulkWrite replaceOne with hints fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "replaceOne": { - "filter": { - "_id": 3 - }, - "replacement": { - "x": 333 - }, - "hint": "_id_" - } - }, - { - "replaceOne": { - "filter": { - "_id": 4 - }, - "replacement": { - "x": 444 - }, - "hint": { - "_id": 1 - } - } - } - ], - "ordered": true - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "Bulkwrite_update_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json deleted file mode 100644 index c5d9f6af3..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-deleteMany-hint-clientError.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "description": "unacknowledged-deleteMany-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "DeleteMany_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "DeleteMany_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged deleteMany with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "DeleteMany_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - ] - }, - { - "description": "Unacknowledged deleteMany with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "DeleteMany_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json deleted file mode 100644 index 177ad889b..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-deleteOne-hint-clientError.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "description": "unacknowledged-deleteOne-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "DeleteOne_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "DeleteOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged deleteOne with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "DeleteOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - }, - { - "description": "Unacknowledged deleteOne with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "deleteOne", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "DeleteOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json deleted file mode 100644 index 6ee59cdf6..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndDelete-hint-clientError.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "description": "unacknowledged-findOneAndDelete-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "findOneAndDelete_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "findOneAndDelete_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged findOneAndDelete with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "findOneAndDelete_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - }, - { - "description": "Unacknowledged findOneAndDelete with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "findOneAndDelete", - "arguments": { - "filter": { - "_id": 1 - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "findOneAndDelete_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json deleted file mode 100644 index 15ca77322..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndReplace-hint-clientError.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "description": "unacknowledged-findOneAndReplace-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "FindOneAndReplace_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "FindOneAndReplace_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged findOneAndReplace with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "FindOneAndReplace_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - }, - { - "description": "Unacknowledged findOneAndReplace with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "findOneAndReplace", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "x": 33 - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "FindOneAndReplace_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json deleted file mode 100644 index e18767f8b..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-findOneAndUpdate-hint-clientError.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "description": "unacknowledged-findOneAndUpdate-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "FindOneAndUpdate_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "FindOneAndUpdate_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged findOneAndUpdate with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "FindOneAndUpdate_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - }, - { - "description": "Unacknowledged findOneAndUpdate with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "findOneAndUpdate", - "arguments": { - "filter": { - "_id": 1 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "FindOneAndUpdate_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json deleted file mode 100644 index 52ec59d0c..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-replaceOne-hint-clientError.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "description": "unacknowledged-replaceOne-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "ReplaceOne_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "ReplaceOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged ReplaceOne with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "ReplaceOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - }, - { - "description": "Unacknowledged ReplaceOne with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "replaceOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "replacement": { - "x": 111 - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "ReplaceOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json deleted file mode 100644 index 6199dfa2b..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-updateMany-hint-clientError.json +++ /dev/null @@ -1,159 +0,0 @@ -{ - "description": "unacknowledged-updateMany-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "Updatemany_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "Updatemany_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged updateMany with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "Updatemany_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - ] - }, - { - "description": "Unacknowledged updateMany with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "Updatemany_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json b/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json deleted file mode 100644 index 3828a9e8d..000000000 --- a/tests/UnifiedSpecTests/crud/unacknowledged-updateOne-hint-clientError.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "description": "unacknowledged-updateOne-hint-clientError", - "schemaVersion": "1.0", - "createEntities": [ - { - "client": { - "id": "client0", - "observeEvents": [ - "commandStartedEvent" - ] - } - }, - { - "database": { - "id": "database0", - "client": "client0", - "databaseName": "crud-v2" - } - }, - { - "collection": { - "id": "collection0", - "database": "database0", - "collectionName": "UpdateOne_hint", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - } - } - } - ], - "initialData": [ - { - "collectionName": "UpdateOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ], - "tests": [ - { - "description": "Unacknowledged updateOne with hint string fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": "_id_" - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "UpdateOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - }, - { - "description": "Unacknowledged updateOne with hint document fails with client-side error", - "operations": [ - { - "object": "collection0", - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - }, - "hint": { - "_id": 1 - } - }, - "expectError": { - "isError": true - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [] - } - ], - "outcome": [ - { - "collectionName": "UpdateOne_hint", - "databaseName": "crud-v2", - "documents": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ] - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/crud/updateMany-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/updateMany-hint-unacknowledged.json new file mode 100644 index 000000000..e83838aac --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-hint-unacknowledged.json @@ -0,0 +1,281 @@ +{ + "description": "updateMany-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged updateMany with hint string fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint document fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint string on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged updateMany with hint document on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateMany", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-hint-unacknowledged.json b/tests/UnifiedSpecTests/crud/updateOne-hint-unacknowledged.json new file mode 100644 index 000000000..859b0f92f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-hint-unacknowledged.json @@ -0,0 +1,281 @@ +{ + "description": "updateOne-hint-unacknowledged", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ], + "tests": [ + { + "description": "Unacknowledged updateOne with hint string fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint document fails with client-side error on pre-4.2 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint string on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": "_id_" + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + }, + { + "description": "Unacknowledged updateOne with hint document on 4.2+ server", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "updateOne", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + }, + "hint": { + "_id": 1 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "acknowledged": { + "$$unsetOrMatches": false + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + }, + "hint": { + "$$type": [ + "string", + "object" + ] + } + } + ], + "writeConcern": { + "w": 0 + } + } + } + } + ] + } + ] + } + ] +} From ce61fc8693213e61495b6bad4f0cddfa05cf0050 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 2 Sep 2021 15:38:55 +0200 Subject: [PATCH 083/321] PHPLIB-683 Test against Proxy as a Mongos (#854) * Split transactions tests for more targeted execution The tests for transactions are the same for the classic and convenient APIs. Since the serverless spec excludes the convenient API from testing, we need to split this so we can only target the classic API for testing. * PHPLIB-684 Add test group annotations for serverless spec tests * PHPLIB-685 Sync tests for serverless testing * PHPLIB-688 Report serverless mode in unified test runner * Support passing authentication options to test framework * Don't run killAllSessions on serverless * PHPLIB-688 Check serverless requirement in legacy spec test runner * PHPLIB-702 Skip crud-v1 tests that use disabled serverless features * PHPLIB-686 Run serverless tests on evergreen * Package serverless for better local debugging * Add note about environment variables overriding URI credentials * PHPLIB-715 Skip failing mapReduce test * Fix wrong driver identifier for serverless tests --- .evergreen/config.yml | 62 +++++++++++++ .evergreen/run-tests.sh | 4 + .evergreen/serverless/create-instance.sh | 87 +++++++++++++++++++ .evergreen/serverless/delete-instance.sh | 40 +++++++++ .evergreen/serverless/get-instance.sh | 37 ++++++++ CONTRIBUTING.md | 9 +- tests/Collection/CrudSpecFunctionalTest.php | 46 ++++++++-- .../spec-tests/read/aggregate-collation.json | 1 + .../spec-tests/read/aggregate-out.json | 21 +---- .../spec-tests/read/count-collation.json | 1 + .../spec-tests/read/distinct-collation.json | 1 + .../spec-tests/read/find-collation.json | 1 + .../spec-tests/write/bulkWrite-collation.json | 1 + .../spec-tests/write/bulkWrite.json | 16 +--- .../write/deleteMany-collation.json | 1 + .../spec-tests/write/deleteOne-collation.json | 1 + .../write/findOneAndDelete-collation.json | 1 + .../write/findOneAndReplace-collation.json | 1 + .../write/findOneAndUpdate-collation.json | 1 + .../write/replaceOne-collation.json | 1 + .../write/updateMany-collation.json | 1 + .../spec-tests/write/updateOne-collation.json | 1 + tests/FunctionalTestCase.php | 44 +++++++++- tests/SpecTests/FunctionalTestCase.php | 35 +++++++- tests/SpecTests/RetryableReadsSpecTest.php | 8 ++ tests/SpecTests/RetryableWritesSpecTest.php | 1 + tests/SpecTests/TransactionsSpecTest.php | 39 ++++++++- .../aggregate-serverErrors.json | 3 +- .../SpecTests/retryable-reads/aggregate.json | 3 +- ...angeStreams-client.watch-serverErrors.json | 6 +- .../changeStreams-client.watch.json | 6 +- ...ngeStreams-db.coll.watch-serverErrors.json | 6 +- .../changeStreams-db.coll.watch.json | 6 +- .../changeStreams-db.watch-serverErrors.json | 6 +- .../changeStreams-db.watch.json | 6 +- .../retryable-reads/count-serverErrors.json | 3 +- tests/SpecTests/retryable-reads/count.json | 3 +- .../countDocuments-serverErrors.json | 3 +- .../retryable-reads/countDocuments.json | 3 +- .../distinct-serverErrors.json | 3 +- tests/SpecTests/retryable-reads/distinct.json | 3 +- .../retryable-reads/find-serverErrors.json | 3 +- tests/SpecTests/retryable-reads/find.json | 3 +- .../retryable-reads/findOne-serverErrors.json | 3 +- tests/SpecTests/retryable-reads/findOne.json | 3 +- .../gridfs-download-serverErrors.json | 3 +- .../retryable-reads/gridfs-download.json | 3 +- .../gridfs-downloadByName-serverErrors.json | 3 +- .../gridfs-downloadByName.json | 3 +- .../listCollectionNames-serverErrors.json | 3 +- .../retryable-reads/listCollectionNames.json | 3 +- .../listCollectionObjects-serverErrors.json | 3 +- .../listCollectionObjects.json | 3 +- .../listCollections-serverErrors.json | 3 +- .../retryable-reads/listCollections.json | 3 +- .../listDatabaseNames-serverErrors.json | 3 +- .../retryable-reads/listDatabaseNames.json | 3 +- .../listDatabaseObjects-serverErrors.json | 3 +- .../retryable-reads/listDatabaseObjects.json | 3 +- .../listDatabases-serverErrors.json | 3 +- .../retryable-reads/listDatabases.json | 3 +- .../listIndexNames-serverErrors.json | 3 +- .../retryable-reads/listIndexNames.json | 3 +- .../listIndexes-serverErrors.json | 3 +- .../retryable-reads/listIndexes.json | 3 +- .../SpecTests/retryable-reads/mapReduce.json | 10 ++- .../bulkWrite-errorLabels.json | 3 +- .../bulkWrite-serverErrors.json | 3 +- .../retryable-writes/deleteMany.json | 3 +- .../deleteOne-errorLabels.json | 3 +- .../deleteOne-serverErrors.json | 3 +- .../findOneAndDelete-errorLabels.json | 3 +- .../findOneAndDelete-serverErrors.json | 3 +- .../findOneAndReplace-errorLabels.json | 3 +- .../findOneAndReplace-serverErrors.json | 3 +- .../findOneAndUpdate-errorLabels.json | 3 +- .../findOneAndUpdate-serverErrors.json | 3 +- .../insertMany-errorLabels.json | 3 +- .../insertMany-serverErrors.json | 3 +- .../insertOne-errorLabels.json | 3 +- .../insertOne-serverErrors.json | 3 +- .../replaceOne-errorLabels.json | 3 +- .../replaceOne-serverErrors.json | 3 +- .../retryable-writes/updateMany.json | 3 +- .../updateOne-errorLabels.json | 3 +- .../updateOne-serverErrors.json | 3 +- .../SpecTests/transactions/error-labels.json | 3 +- .../transactions/mongos-pin-auto.json | 3 +- .../transactions/mongos-recovery-token.json | 3 +- tests/SpecTests/transactions/pin-mongos.json | 3 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 3 + tests/UnifiedSpecTests/UnifiedTestRunner.php | 11 ++- .../UnifiedSpecTests/crud/aggregate-let.json | 5 +- .../crud/aggregate-out-readConcern.json | 5 +- 94 files changed, 572 insertions(+), 128 deletions(-) create mode 100755 .evergreen/serverless/create-instance.sh create mode 100755 .evergreen/serverless/delete-instance.sh create mode 100755 .evergreen/serverless/get-instance.sh diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 1c2d6a43a..877faf0ef 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -199,6 +199,38 @@ functions: script: | DRIVERS_TOOLS="${DRIVERS_TOOLS}" sh ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/run-mongohouse-local.sh + "create serverless instance": + - command: shell.exec + params: + working_dir: "src" + shell: bash + script: |- + ${PREPARE_SHELL} + export PROJECT=${PROJECT} + export SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} + export SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} + export SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} + export SERVERLESS_ATLAS_USER=${SERVERLESS_ATLAS_USER} + export SERVERLESS_ATLAS_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} + sh ${PROJECT_DIRECTORY}/.evergreen/serverless/create-instance.sh + - command: expansions.update + params: + file: src/serverless-expansion.yml + + "delete serverless instance": + - command: shell.exec + params: + shell: bash + script: |- + set -o errexit + export SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} + export SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} + export SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} + export SERVERLESS_ATLAS_USER=${SERVERLESS_ATLAS_USER} + export SERVERLESS_ATLAS_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} + export SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} + sh ${PROJECT_DIRECTORY}/.evergreen/serverless/delete-instance.sh + "run tests": - command: shell.exec type: test @@ -226,6 +258,20 @@ functions: export PATH="${PHP_PATH}/bin:$PATH" PHP_VERSION=${PHP_VERSION} TESTS="atlas-data-lake" AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + "run serverless tests": + - command: shell.exec + type: test + params: + working_dir: "src" + shell: bash + script: |- + ${PREPARE_SHELL} + export MONGODB_IS_SERVERLESS=on + export MONGODB_USERNAME=${SERVERLESS_ATLAS_USER} + export MONGODB_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} + export PATH="${PHP_PATH}/bin:$PATH" + PHP_VERSION=${PHP_VERSION} TESTS="serverless" MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + "cleanup": - command: shell.exec params: @@ -377,6 +423,15 @@ tasks: - func: "run tests" vars: TESTS: "versioned-api" + + - name: "test-serverless" + tags: ["serverless"] + commands: + - func: "create serverless instance" + vars: + PROJECT: "mongo-php-library" + - func: "run serverless tests" + - func: "delete serverless instance" # }}} @@ -631,3 +686,10 @@ buildvariants: run_on: rhel70 tasks: - .versioned-api + +- matrix_name: "serverless" + matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-dev" } + display_name: "Serverless" + run_on: rhel70 + tasks: + - .serverless diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index eb78a6893..5cf1978cd 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -63,6 +63,10 @@ case "$TESTS" in php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group versioned-api $PHPUNIT_OPTS ;; + serverless) + php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group serverless $PHPUNIT_OPTS + ;; + *) php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml $PHPUNIT_OPTS ;; diff --git a/.evergreen/serverless/create-instance.sh b/.evergreen/serverless/create-instance.sh new file mode 100755 index 000000000..0a56c8e33 --- /dev/null +++ b/.evergreen/serverless/create-instance.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +set -o errexit +set +o xtrace # disable xtrace to ensure credentials aren't leaked + +if [ -z "$PROJECT" ]; then + echo "Project name must be provided via PROJECT environment variable" + exit 1 +fi +INSTANCE_NAME="$RANDOM-$PROJECT" + +if [ -z "$SERVERLESS_DRIVERS_GROUP" ]; then + echo "Drivers Atlas group must be provided via SERVERLESS_DRIVERS_GROUP environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_API_PRIVATE_KEY" ]; then + echo "Atlas API private key must be provided via SERVERLESS_API_PRIVATE_KEY environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_API_PUBLIC_KEY" ]; then + echo "Atlas API public key must be provided via SERVERLESS_API_PUBLIC_KEY environment variable" + exit 1 +fi + +echo "creating new serverless instance \"${INSTANCE_NAME}\"..." + +DIR=$(dirname $0) +API_BASE_URL="https://account-dev.mongodb.com/api/atlas/v1.0/groups/$SERVERLESS_DRIVERS_GROUP" + +curl \ + -u "$SERVERLESS_API_PUBLIC_KEY:$SERVERLESS_API_PRIVATE_KEY" \ + --silent \ + --show-error \ + -X POST \ + --digest \ + --header "Accept: application/json" \ + --header "Content-Type: application/json" \ + "$API_BASE_URL/serverless?pretty=true" \ + --data " + { + \"name\" : \"${INSTANCE_NAME}\", + \"providerSettings\" : { + \"providerName\": \"SERVERLESS\", + \"backingProviderName\": \"GCP\", + \"instanceSizeName\" : \"SERVERLESS_V2\", + \"regionName\" : \"CENTRAL_US\" + } + }" + +echo "" + +if [ "Windows_NT" = "$OS" ]; then + PYTHON_BINARY=C:/python/Python38/python.exe +else + PYTHON_BINARY=python +fi + +SECONDS=0 +while [ true ]; do + API_RESPONSE=`SERVERLESS_INSTANCE_NAME=$INSTANCE_NAME bash $DIR/get-instance.sh` + STATE_NAME=`echo $API_RESPONSE | $PYTHON_BINARY -c "import sys, json; print(json.load(sys.stdin)['stateName'])" | tr -d '\r\n'` + + if [ "$STATE_NAME" = "IDLE" ]; then + duration="$SECONDS" + echo "setup done! ($(($duration / 60))m $(($duration % 60))s elapsed)" + echo "SERVERLESS_INSTANCE_NAME=\"$INSTANCE_NAME\"" + SRV_ADDRESS=$(echo $API_RESPONSE | $PYTHON_BINARY -c "import sys, json; print(json.load(sys.stdin)['connectionStrings']['standardSrv'])" | tr -d '\r\n') + echo "MONGODB_SRV_URI=\"$SRV_ADDRESS\"" + STANDARD_ADDRESS=$(echo $API_RESPONSE | $PYTHON_BINARY -c "import sys, json; print(json.load(sys.stdin)['connectionStrings']['standard'].replace('&authSource=admin', ''))" | tr -d '\r\n') + echo "MONGODB_URI=\"$STANDARD_ADDRESS\"" + cat < serverless-expansion.yml +MONGODB_URI: "$STANDARD_ADDRESS" +MONGODB_SRV_URI: "$SRV_ADDRESS" +SERVERLESS_INSTANCE_NAME: "$INSTANCE_NAME" +SSL: ssl +AUTH: auth +TOPOLOGY: sharded_cluster +SERVERLESS: serverless +EOF + exit 0 + else + echo "setup still in progress, status=$STATE_NAME, sleeping for 1 minute..." + sleep 60 + fi +done diff --git a/.evergreen/serverless/delete-instance.sh b/.evergreen/serverless/delete-instance.sh new file mode 100755 index 000000000..ba412d4d4 --- /dev/null +++ b/.evergreen/serverless/delete-instance.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -o errexit +set +o xtrace + +if [ -z "$SERVERLESS_INSTANCE_NAME" ]; then + echo "Instance name must be provided via SERVERLESS_INSTANCE_NAME environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_DRIVERS_GROUP" ]; then + echo "Drivers Atlas group must be provided via SERVERLESS_DRIVERS_GROUP environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_API_PRIVATE_KEY" ]; then + echo "Atlas API private key must be provided via SERVERLESS_API_PRIVATE_KEY environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_API_PUBLIC_KEY" ]; then + echo "Atlas API public key must be provided via SERVERLESS_API_PUBLIC_KEY environment variable" + exit 1 +fi + +echo "deleting serverless instance \"${SERVERLESS_INSTANCE_NAME}\"..." + +API_BASE_URL="https://account-dev.mongodb.com/api/atlas/v1.0/groups/$SERVERLESS_DRIVERS_GROUP" + +curl \ + --silent \ + --show-error \ + -u "$SERVERLESS_API_PUBLIC_KEY:$SERVERLESS_API_PRIVATE_KEY" \ + -X DELETE \ + --digest \ + --header "Accept: application/json" \ + --header "Content-Type: application/json" \ + "${API_BASE_URL}/serverless/${SERVERLESS_INSTANCE_NAME}?pretty=true" + +echo "" diff --git a/.evergreen/serverless/get-instance.sh b/.evergreen/serverless/get-instance.sh new file mode 100755 index 000000000..496400dc7 --- /dev/null +++ b/.evergreen/serverless/get-instance.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +set -o errexit +set +o xtrace + +if [ -z "$SERVERLESS_INSTANCE_NAME" ]; then + echo "Instance name must be provided via SERVERLESS_INSTANCE_NAME environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_DRIVERS_GROUP" ]; then + echo "Drivers Atlas group must be provided via SERVERLESS_DRIVERS_GROUP environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_API_PRIVATE_KEY" ]; then + echo "Atlas API private key must be provided via SERVERLESS_API_PRIVATE_KEY environment variable" + exit 1 +fi + +if [ -z "$SERVERLESS_API_PUBLIC_KEY" ]; then + echo "Atlas API public key must be provided via SERVERLESS_API_PUBLIC_KEY environment variable" + exit 1 +fi + +API_BASE_URL="https://account-dev.mongodb.com/api/private/nds/serverless/groups/$SERVERLESS_DRIVERS_GROUP" + +curl \ + --silent \ + --show-error \ + -u "$SERVERLESS_API_PUBLIC_KEY:$SERVERLESS_API_PRIVATE_KEY" \ + -X GET \ + --digest \ + --header "Accept: application/json" \ + "${API_BASE_URL}/instances/${SERVERLESS_INSTANCE_NAME}?pretty=true" \ + +echo "" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index db1db742b..ee2d45332 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,7 +34,14 @@ The `phpunit.xml.dist` file is used as the default configuration file for the test suite. In addition to various PHPUnit options, it defines required `MONGODB_URI` and `MONGODB_DATABASE` environment variables. You may customize this configuration by creating your own `phpunit.xml` file based on the -`phpunit.xml.dist` file we provide. +`phpunit.xml.dist` file we provide. To run the tests in serverless mode, set the +`MONGODB_IS_SERVERLESS` environment variable to `on`. + +To run tests against a cluster that requires authentication, either include the +credentials in the connection string given in the `MONGODB_URI` environment +variable, or set the `MONGODB_USERNAME` and `MONGODB_PASSWORD` environment +variables accordingly. Note that values defined through the environment override +credentials present in the URI. By default, the `simple-phpunit` binary chooses the correct PHPUnit version for the PHP version you are running. To run tests against a specific PHPUnit version, diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index 398b6a4aa..f1cc519b6 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -32,10 +32,15 @@ * * @see https://github.com/mongodb/specifications/tree/master/source/crud/tests * + * @group serverless * @group matrix-testing-exclude-server-5.0-driver-4.0 */ class CrudSpecFunctionalTest extends FunctionalTestCase { + public const SERVERLESS_ALLOW = 'allow'; + public const SERVERLESS_FORBID = 'forbid'; + public const SERVERLESS_REQUIRE = 'require'; + /** @var Collection */ private $expectedCollection; @@ -50,12 +55,14 @@ public function setUp(): void /** * @dataProvider provideSpecificationTests */ - public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion): void + public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion, $serverless): void { if (isset($minServerVersion) || isset($maxServerVersion)) { $this->checkServerVersion($minServerVersion, $maxServerVersion); } + $this->checkServerlessRequirement($serverless); + $expectedData = $test['outcome']['collection']['data'] ?? null; $this->initializeData($initialData, $expectedData); @@ -83,12 +90,15 @@ public function provideSpecificationTests() foreach (glob(__DIR__ . '/spec-tests/*/*.json') as $filename) { $json = json_decode(file_get_contents($filename), true); - $minServerVersion = $json['minServerVersion'] ?? null; - $maxServerVersion = $json['maxServerVersion'] ?? null; - foreach ($json['tests'] as $test) { $name = str_replace(' ', '_', $test['description']); - $testArgs[$name] = [$json['data'], $test, $minServerVersion, $maxServerVersion]; + $testArgs[$name] = [ + $json['data'], + $test, + $json['minServerVersion'] ?? null, + $json['maxServerVersion'] ?? null, + $json['serverless'] ?? null, + ]; } } @@ -113,6 +123,32 @@ private function assertEquivalentCollections(Collection $expectedCollection, Col } } + private function checkServerlessRequirement(?string $serverless): void + { + switch ($serverless) { + case null: + case self::SERVERLESS_ALLOW: + return; + + case self::SERVERLESS_FORBID: + if ($this->isServerless()) { + $this->markTestSkipped('Test does not apply on serverless'); + } + + return; + + case self::SERVERLESS_REQUIRE: + if (! $this->isServerless()) { + $this->markTestSkipped('Test requires serverless'); + } + + return; + + default: + $this->fail(sprintf('Unknown serverless requirement "%s".', $serverless)); + } + } + /** * Checks that the server version is within the allowed bounds (if any). * diff --git a/tests/Collection/spec-tests/read/aggregate-collation.json b/tests/Collection/spec-tests/read/aggregate-collation.json index 85662a442..d958e447b 100644 --- a/tests/Collection/spec-tests/read/aggregate-collation.json +++ b/tests/Collection/spec-tests/read/aggregate-collation.json @@ -6,6 +6,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "Aggregate with collation", diff --git a/tests/Collection/spec-tests/read/aggregate-out.json b/tests/Collection/spec-tests/read/aggregate-out.json index 205cf7657..c195e163e 100644 --- a/tests/Collection/spec-tests/read/aggregate-out.json +++ b/tests/Collection/spec-tests/read/aggregate-out.json @@ -14,6 +14,7 @@ } ], "minServerVersion": "2.6", + "serverless": "forbid", "tests": [ { "description": "Aggregate with $out", @@ -41,16 +42,6 @@ } }, "outcome": { - "result": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], "collection": { "name": "other_test_collection", "data": [ @@ -92,16 +83,6 @@ } }, "outcome": { - "result": [ - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], "collection": { "name": "other_test_collection", "data": [ diff --git a/tests/Collection/spec-tests/read/count-collation.json b/tests/Collection/spec-tests/read/count-collation.json index 6f75282fe..7d6150849 100644 --- a/tests/Collection/spec-tests/read/count-collation.json +++ b/tests/Collection/spec-tests/read/count-collation.json @@ -6,6 +6,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "Count documents with collation", diff --git a/tests/Collection/spec-tests/read/distinct-collation.json b/tests/Collection/spec-tests/read/distinct-collation.json index 0af0c67cb..984991a43 100644 --- a/tests/Collection/spec-tests/read/distinct-collation.json +++ b/tests/Collection/spec-tests/read/distinct-collation.json @@ -10,6 +10,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "Distinct with a collation", diff --git a/tests/Collection/spec-tests/read/find-collation.json b/tests/Collection/spec-tests/read/find-collation.json index 53d0e9490..4e56c0525 100644 --- a/tests/Collection/spec-tests/read/find-collation.json +++ b/tests/Collection/spec-tests/read/find-collation.json @@ -6,6 +6,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "Find with a collation", diff --git a/tests/Collection/spec-tests/write/bulkWrite-collation.json b/tests/Collection/spec-tests/write/bulkWrite-collation.json index 8e9d1bcb1..bc90aa817 100644 --- a/tests/Collection/spec-tests/write/bulkWrite-collation.json +++ b/tests/Collection/spec-tests/write/bulkWrite-collation.json @@ -22,6 +22,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "BulkWrite with delete operations and collation", diff --git a/tests/Collection/spec-tests/write/bulkWrite.json b/tests/Collection/spec-tests/write/bulkWrite.json index 97879e7d3..dc00da28a 100644 --- a/tests/Collection/spec-tests/write/bulkWrite.json +++ b/tests/Collection/spec-tests/write/bulkWrite.json @@ -188,18 +188,6 @@ } } }, - { - "name": "replaceOne", - "arguments": { - "filter": { - "_id": 1 - }, - "replacement": { - "_id": 1, - "x": 11 - } - } - }, { "name": "replaceOne", "arguments": { @@ -234,11 +222,11 @@ "deletedCount": 0, "insertedCount": 0, "insertedIds": {}, - "matchedCount": 2, + "matchedCount": 1, "modifiedCount": 1, "upsertedCount": 1, "upsertedIds": { - "3": 3 + "2": 3 } }, "collection": { diff --git a/tests/Collection/spec-tests/write/deleteMany-collation.json b/tests/Collection/spec-tests/write/deleteMany-collation.json index d17bf3bcb..fce75e488 100644 --- a/tests/Collection/spec-tests/write/deleteMany-collation.json +++ b/tests/Collection/spec-tests/write/deleteMany-collation.json @@ -14,6 +14,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "DeleteMany when many documents match with collation", diff --git a/tests/Collection/spec-tests/write/deleteOne-collation.json b/tests/Collection/spec-tests/write/deleteOne-collation.json index 2f7f92113..9bcef411e 100644 --- a/tests/Collection/spec-tests/write/deleteOne-collation.json +++ b/tests/Collection/spec-tests/write/deleteOne-collation.json @@ -14,6 +14,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "DeleteOne when many documents matches with collation", diff --git a/tests/Collection/spec-tests/write/findOneAndDelete-collation.json b/tests/Collection/spec-tests/write/findOneAndDelete-collation.json index 1ff37d2e8..32480da84 100644 --- a/tests/Collection/spec-tests/write/findOneAndDelete-collation.json +++ b/tests/Collection/spec-tests/write/findOneAndDelete-collation.json @@ -14,6 +14,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "FindOneAndDelete when one document matches with collation", diff --git a/tests/Collection/spec-tests/write/findOneAndReplace-collation.json b/tests/Collection/spec-tests/write/findOneAndReplace-collation.json index babb2f7c1..9b3c25005 100644 --- a/tests/Collection/spec-tests/write/findOneAndReplace-collation.json +++ b/tests/Collection/spec-tests/write/findOneAndReplace-collation.json @@ -10,6 +10,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "FindOneAndReplace when one document matches with collation returning the document after modification", diff --git a/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json b/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json index 04c1fe73e..8abab7bd6 100644 --- a/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json +++ b/tests/Collection/spec-tests/write/findOneAndUpdate-collation.json @@ -14,6 +14,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "FindOneAndUpdate when many documents match with collation returning the document before modification", diff --git a/tests/Collection/spec-tests/write/replaceOne-collation.json b/tests/Collection/spec-tests/write/replaceOne-collation.json index a668fe738..fa4cbe997 100644 --- a/tests/Collection/spec-tests/write/replaceOne-collation.json +++ b/tests/Collection/spec-tests/write/replaceOne-collation.json @@ -10,6 +10,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "ReplaceOne when one document matches with collation", diff --git a/tests/Collection/spec-tests/write/updateMany-collation.json b/tests/Collection/spec-tests/write/updateMany-collation.json index 3cb49f229..8becfd806 100644 --- a/tests/Collection/spec-tests/write/updateMany-collation.json +++ b/tests/Collection/spec-tests/write/updateMany-collation.json @@ -14,6 +14,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "UpdateMany when many documents match with collation", diff --git a/tests/Collection/spec-tests/write/updateOne-collation.json b/tests/Collection/spec-tests/write/updateOne-collation.json index c49112d51..3afdb83e0 100644 --- a/tests/Collection/spec-tests/write/updateOne-collation.json +++ b/tests/Collection/spec-tests/write/updateOne-collation.json @@ -10,6 +10,7 @@ } ], "minServerVersion": "3.4", + "serverless": "forbid", "tests": [ { "description": "UpdateOne when one document matches with collation", diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 38877c92b..3a70f34ff 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -25,6 +25,7 @@ use function count; use function current; use function explode; +use function filter_var; use function getenv; use function implode; use function is_array; @@ -42,6 +43,7 @@ use function sprintf; use function version_compare; +use const FILTER_VALIDATE_BOOLEAN; use const INFO_MODULES; abstract class FunctionalTestCase extends TestCase @@ -69,12 +71,20 @@ public function tearDown(): void public static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client { - return new Client($uri ?? static::getUri(), $options, static::appendServerApiOption($driverOptions)); + return new Client( + $uri ?? static::getUri(), + static::appendAuthenticationOptions($options), + static::appendServerApiOption($driverOptions) + ); } public static function createTestManager(?string $uri = null, array $options = [], array $driverOptions = []): Manager { - return new Manager($uri ?? static::getUri(), $options, static::appendServerApiOption($driverOptions)); + return new Manager( + $uri ?? static::getUri(), + static::appendAuthenticationOptions($options), + static::appendServerApiOption($driverOptions) + ); } public static function getUri($allowMultipleMongoses = false): string @@ -385,6 +395,16 @@ protected function isReplicaSet() return $this->getPrimaryServer()->getType() == Server::TYPE_RS_PRIMARY; } + /** + * Return whether serverless (i.e. proxy as mongos) is being utilized. + */ + protected static function isServerless(): bool + { + $isServerless = getenv('MONGODB_IS_SERVERLESS'); + + return $isServerless !== false ? filter_var($isServerless, FILTER_VALIDATE_BOOLEAN) : false; + } + protected function isShardedCluster() { return $this->getPrimaryServer()->getType() == Server::TYPE_MONGOS; @@ -513,6 +533,26 @@ protected function skipIfTransactionsAreNotSupported(): void } } + private static function appendAuthenticationOptions(array $options): array + { + if (isset($options['username']) || isset($options['password'])) { + return $options; + } + + $username = getenv('MONGODB_USERNAME') ?: null; + $password = getenv('MONGODB_PASSWORD') ?: null; + + if ($username !== null) { + $options['username'] = $username; + } + + if ($password !== null) { + $options['password'] = $password; + } + + return $options; + } + private static function appendServerApiOption(array $driverOptions): array { if (getenv('API_VERSION') && ! isset($driverOptions['serverApi'])) { diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index 9c6939639..d9738c568 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -30,6 +30,10 @@ class FunctionalTestCase extends BaseFunctionalTestCase public const TOPOLOGY_REPLICASET = 'replicaset'; public const TOPOLOGY_SHARDED = 'sharded'; + public const SERVERLESS_ALLOW = 'allow'; + public const SERVERLESS_FORBID = 'forbid'; + public const SERVERLESS_REQUIRE = 'require'; + /** @var Context|null */ private $context; @@ -137,8 +141,9 @@ protected function checkServerRequirements(array $runOn): void $minServerVersion = $req->minServerVersion ?? null; $maxServerVersion = $req->maxServerVersion ?? null; $topologies = $req->topology ?? null; + $serverlessMode = $req->serverless ?? null; - if ($this->isServerRequirementSatisifed($minServerVersion, $maxServerVersion, $topologies)) { + if ($this->isServerRequirementSatisifed($minServerVersion, $maxServerVersion, $topologies, $serverlessMode)) { return; } } @@ -268,7 +273,27 @@ private function getTopology(): string return $topologyTypeMap[$primaryType]; } - throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); + throw new UnexpectedValueException(sprintf('Cannot find topology for primary of type "%s".', $primaryType)); + } + + private function isServerlessRequirementSatisfied(?string $serverlessMode): bool + { + if ($serverlessMode === null) { + return true; + } + + switch ($serverlessMode) { + case self::SERVERLESS_ALLOW: + return true; + + case self::SERVERLESS_FORBID: + return ! static::isServerless(); + + case self::SERVERLESS_REQUIRE: + return static::isServerless(); + } + + throw new UnexpectedValueException(sprintf('Invalid serverless requirement "%s" found.', $serverlessMode)); } /** @@ -279,7 +304,7 @@ private function getTopology(): string * @param array|null $topologies * @return boolean */ - private function isServerRequirementSatisifed(?string $minServerVersion, ?string $maxServerVersion, ?array $topologies = null): bool + private function isServerRequirementSatisifed(?string $minServerVersion, ?string $maxServerVersion, ?array $topologies = null, ?string $serverlessMode = null): bool { $serverVersion = $this->getServerVersion(); @@ -297,6 +322,10 @@ private function isServerRequirementSatisifed(?string $minServerVersion, ?string return false; } + if (! $this->isServerlessRequirementSatisfied($serverlessMode)) { + return false; + } + return true; } } diff --git a/tests/SpecTests/RetryableReadsSpecTest.php b/tests/SpecTests/RetryableReadsSpecTest.php index 3f16f4324..1498a34b2 100644 --- a/tests/SpecTests/RetryableReadsSpecTest.php +++ b/tests/SpecTests/RetryableReadsSpecTest.php @@ -14,6 +14,7 @@ * Retryable reads spec tests. * * @see https://github.com/mongodb/specifications/tree/master/source/retryable-reads + * @group serverless */ class RetryableReadsSpecTest extends FunctionalTestCase { @@ -24,6 +25,9 @@ class RetryableReadsSpecTest extends FunctionalTestCase 'listIndexNames' => 'Not implemented', ]; + /** @var array */ + private static $incompleteTests = ['mapReduce: MapReduce succeeds with retry on' => 'PHPLIB-715']; + /** * Assert that the expected and actual command documents match. * @@ -65,6 +69,10 @@ public function testRetryableReads(stdClass $test, ?array $runOn = null, $data, $this->skipIfChangeStreamIsNotSupported(); } + if (isset(self::$incompleteTests[$this->dataDescription()])) { + $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); + } + $context = Context::fromRetryableReads($test, $databaseName, $collectionName, $bucketName); $this->setContext($context); diff --git a/tests/SpecTests/RetryableWritesSpecTest.php b/tests/SpecTests/RetryableWritesSpecTest.php index 8f9ffaf97..aa9f9083d 100644 --- a/tests/SpecTests/RetryableWritesSpecTest.php +++ b/tests/SpecTests/RetryableWritesSpecTest.php @@ -12,6 +12,7 @@ * Retryable writes spec tests. * * @see https://github.com/mongodb/specifications/tree/master/source/retryable-writes + * @group serverless */ class RetryableWritesSpecTest extends FunctionalTestCase { diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 1829ed6a1..165f3c255 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -110,17 +110,43 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual static::assertDocumentsMatch($expected, $actual); } + /** + * @dataProvider provideTransactionsTests + * @group serverless + */ + public function testTransactions(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + { + $this->runTransactionTest($test, $runOn, $data, $databaseName, $collectionName); + } + + public function provideTransactionsTests(): array + { + return $this->provideTests('transactions'); + } + + /** + * @dataProvider provideTransactionsConvenientApiTests + */ + public function testTransactionsConvenientApi(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + { + $this->runTransactionTest($test, $runOn, $data, $databaseName, $collectionName); + } + + public function provideTransactionsConvenientApiTests(): array + { + return $this->provideTests('transactions-convenient-api'); + } + /** * Execute an individual test case from the specification. * - * @dataProvider provideTests * @param stdClass $test Individual "tests[]" document * @param array $runOn Top-level "runOn" array with server requirements * @param array $data Top-level "data" array to initialize collection * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testTransactions(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + private function runTransactionTest(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); @@ -173,11 +199,11 @@ public function testTransactions(stdClass $test, ?array $runOn = null, array $da } } - public function provideTests() + private function provideTests(string $dir): array { $testArgs = []; - foreach (glob(__DIR__ . '/transactions*/*.json') as $filename) { + foreach (glob(__DIR__ . '/' . $dir . '/*.json') as $filename) { $json = $this->decodeJson(file_get_contents($filename)); $group = basename(dirname($filename)) . '/' . basename($filename, '.json'); $runOn = $json->runOn ?? null; @@ -290,6 +316,11 @@ protected function createTestCollection(): void */ private static function killAllSessions(): void { + // killAllSessions is not supported on serverless, see CLOUDP-84298 + if (static::isServerless()) { + return; + } + $manager = static::createTestManager(); $primary = $manager->selectServer(new ReadPreference('primary')); diff --git a/tests/SpecTests/retryable-reads/aggregate-serverErrors.json b/tests/SpecTests/retryable-reads/aggregate-serverErrors.json index f6197cc9f..1155f808d 100644 --- a/tests/SpecTests/retryable-reads/aggregate-serverErrors.json +++ b/tests/SpecTests/retryable-reads/aggregate-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/aggregate.json b/tests/SpecTests/retryable-reads/aggregate.json index 30a6e05e6..f23d5c679 100644 --- a/tests/SpecTests/retryable-reads/aggregate.json +++ b/tests/SpecTests/retryable-reads/aggregate.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json b/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json index f67ee8d30..73dbfee91 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json +++ b/tests/SpecTests/retryable-reads/changeStreams-client.watch-serverErrors.json @@ -9,8 +9,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", diff --git a/tests/SpecTests/retryable-reads/changeStreams-client.watch.json b/tests/SpecTests/retryable-reads/changeStreams-client.watch.json index 9a2ccad09..30a53037a 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-client.watch.json +++ b/tests/SpecTests/retryable-reads/changeStreams-client.watch.json @@ -9,8 +9,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", diff --git a/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json b/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json index 63514f6a8..77b3af04f 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json +++ b/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch-serverErrors.json @@ -9,8 +9,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", diff --git a/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch.json b/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch.json index 3408c8423..27f6105a4 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch.json +++ b/tests/SpecTests/retryable-reads/changeStreams-db.coll.watch.json @@ -9,8 +9,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", diff --git a/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json b/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json index 8d1624240..7a8753450 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json +++ b/tests/SpecTests/retryable-reads/changeStreams-db.watch-serverErrors.json @@ -9,8 +9,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", diff --git a/tests/SpecTests/retryable-reads/changeStreams-db.watch.json b/tests/SpecTests/retryable-reads/changeStreams-db.watch.json index bec09c49b..e6b0b9b78 100644 --- a/tests/SpecTests/retryable-reads/changeStreams-db.watch.json +++ b/tests/SpecTests/retryable-reads/changeStreams-db.watch.json @@ -9,8 +9,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", diff --git a/tests/SpecTests/retryable-reads/count-serverErrors.json b/tests/SpecTests/retryable-reads/count-serverErrors.json index 1de695eb8..36a0c17ca 100644 --- a/tests/SpecTests/retryable-reads/count-serverErrors.json +++ b/tests/SpecTests/retryable-reads/count-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/count.json b/tests/SpecTests/retryable-reads/count.json index 0ccf4982b..139a54513 100644 --- a/tests/SpecTests/retryable-reads/count.json +++ b/tests/SpecTests/retryable-reads/count.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json b/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json index 8e7a1b58e..782ea5e4f 100644 --- a/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json +++ b/tests/SpecTests/retryable-reads/countDocuments-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/countDocuments.json b/tests/SpecTests/retryable-reads/countDocuments.json index b4ccf3668..57a64e45b 100644 --- a/tests/SpecTests/retryable-reads/countDocuments.json +++ b/tests/SpecTests/retryable-reads/countDocuments.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/distinct-serverErrors.json b/tests/SpecTests/retryable-reads/distinct-serverErrors.json index c168b37ec..d7c6018a6 100644 --- a/tests/SpecTests/retryable-reads/distinct-serverErrors.json +++ b/tests/SpecTests/retryable-reads/distinct-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/distinct.json b/tests/SpecTests/retryable-reads/distinct.json index b5885e27e..1fd415da8 100644 --- a/tests/SpecTests/retryable-reads/distinct.json +++ b/tests/SpecTests/retryable-reads/distinct.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/find-serverErrors.json b/tests/SpecTests/retryable-reads/find-serverErrors.json index 3d1cfa456..f6b96c6dc 100644 --- a/tests/SpecTests/retryable-reads/find-serverErrors.json +++ b/tests/SpecTests/retryable-reads/find-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/find.json b/tests/SpecTests/retryable-reads/find.json index 56479ff1d..00d419c0d 100644 --- a/tests/SpecTests/retryable-reads/find.json +++ b/tests/SpecTests/retryable-reads/find.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/findOne-serverErrors.json b/tests/SpecTests/retryable-reads/findOne-serverErrors.json index 161dc42f3..d039ef247 100644 --- a/tests/SpecTests/retryable-reads/findOne-serverErrors.json +++ b/tests/SpecTests/retryable-reads/findOne-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/findOne.json b/tests/SpecTests/retryable-reads/findOne.json index d296a9cdb..b9deb73d2 100644 --- a/tests/SpecTests/retryable-reads/findOne.json +++ b/tests/SpecTests/retryable-reads/findOne.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json b/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json index af091d679..cec3a5016 100644 --- a/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json +++ b/tests/SpecTests/retryable-reads/gridfs-download-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/gridfs-download.json b/tests/SpecTests/retryable-reads/gridfs-download.json index a5c5ef4d5..4d0d5a17e 100644 --- a/tests/SpecTests/retryable-reads/gridfs-download.json +++ b/tests/SpecTests/retryable-reads/gridfs-download.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json b/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json index 61e3a5947..a64230d38 100644 --- a/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json +++ b/tests/SpecTests/retryable-reads/gridfs-downloadByName-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/gridfs-downloadByName.json b/tests/SpecTests/retryable-reads/gridfs-downloadByName.json index 0634a09bf..48f2168cf 100644 --- a/tests/SpecTests/retryable-reads/gridfs-downloadByName.json +++ b/tests/SpecTests/retryable-reads/gridfs-downloadByName.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json b/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json index a07e746a5..bbdce625a 100644 --- a/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listCollectionNames-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listCollectionNames.json b/tests/SpecTests/retryable-reads/listCollectionNames.json index 437fc36a4..73d96a3cf 100644 --- a/tests/SpecTests/retryable-reads/listCollectionNames.json +++ b/tests/SpecTests/retryable-reads/listCollectionNames.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json b/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json index c2d4358fb..ab469dfe3 100644 --- a/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listCollectionObjects-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listCollectionObjects.json b/tests/SpecTests/retryable-reads/listCollectionObjects.json index 1f537b743..1fb0f1843 100644 --- a/tests/SpecTests/retryable-reads/listCollectionObjects.json +++ b/tests/SpecTests/retryable-reads/listCollectionObjects.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listCollections-serverErrors.json b/tests/SpecTests/retryable-reads/listCollections-serverErrors.json index f749c8c27..def9ac459 100644 --- a/tests/SpecTests/retryable-reads/listCollections-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listCollections-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listCollections.json b/tests/SpecTests/retryable-reads/listCollections.json index a6b452e64..242788362 100644 --- a/tests/SpecTests/retryable-reads/listCollections.json +++ b/tests/SpecTests/retryable-reads/listCollections.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json b/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json index 959d70fb3..1dd8e4415 100644 --- a/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listDatabaseNames-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listDatabaseNames.json b/tests/SpecTests/retryable-reads/listDatabaseNames.json index b35f7ab18..b431f5701 100644 --- a/tests/SpecTests/retryable-reads/listDatabaseNames.json +++ b/tests/SpecTests/retryable-reads/listDatabaseNames.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json b/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json index 6b95b421a..bc497bb08 100644 --- a/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listDatabaseObjects-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listDatabaseObjects.json b/tests/SpecTests/retryable-reads/listDatabaseObjects.json index cbd2c6763..267fe921c 100644 --- a/tests/SpecTests/retryable-reads/listDatabaseObjects.json +++ b/tests/SpecTests/retryable-reads/listDatabaseObjects.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json b/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json index 1393f5f89..ed7bcbc39 100644 --- a/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listDatabases-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listDatabases.json b/tests/SpecTests/retryable-reads/listDatabases.json index 3cb8bbd08..69ef9788f 100644 --- a/tests/SpecTests/retryable-reads/listDatabases.json +++ b/tests/SpecTests/retryable-reads/listDatabases.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json b/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json index 04d60f100..2d3265ec8 100644 --- a/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listIndexNames-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listIndexNames.json b/tests/SpecTests/retryable-reads/listIndexNames.json index 912c70601..fbdb420f8 100644 --- a/tests/SpecTests/retryable-reads/listIndexNames.json +++ b/tests/SpecTests/retryable-reads/listIndexNames.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json b/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json index ccf385c5b..25c5b0e44 100644 --- a/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json +++ b/tests/SpecTests/retryable-reads/listIndexes-serverErrors.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/listIndexes.json b/tests/SpecTests/retryable-reads/listIndexes.json index f460ea768..5cb620ae4 100644 --- a/tests/SpecTests/retryable-reads/listIndexes.json +++ b/tests/SpecTests/retryable-reads/listIndexes.json @@ -10,7 +10,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-reads/mapReduce.json b/tests/SpecTests/retryable-reads/mapReduce.json index 3cb35fd49..9327a2305 100644 --- a/tests/SpecTests/retryable-reads/mapReduce.json +++ b/tests/SpecTests/retryable-reads/mapReduce.json @@ -10,8 +10,10 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" - ] + "sharded", + "load-balanced" + ], + "serverless": "forbid" } ], "database_name": "retryable-reads-tests", @@ -50,8 +52,8 @@ }, "result": [ { - "_id": 0.0, - "value": 6.0 + "_id": 0, + "value": 6 } ] } diff --git a/tests/SpecTests/retryable-writes/bulkWrite-errorLabels.json b/tests/SpecTests/retryable-writes/bulkWrite-errorLabels.json index 94ea3ea98..66c3ecb33 100644 --- a/tests/SpecTests/retryable-writes/bulkWrite-errorLabels.json +++ b/tests/SpecTests/retryable-writes/bulkWrite-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json b/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json index d9561d568..9d792ceaf 100644 --- a/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json +++ b/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/deleteMany.json b/tests/SpecTests/retryable-writes/deleteMany.json index 642ad11fb..faa21c44f 100644 --- a/tests/SpecTests/retryable-writes/deleteMany.json +++ b/tests/SpecTests/retryable-writes/deleteMany.json @@ -4,7 +4,8 @@ "minServerVersion": "3.6", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/deleteOne-errorLabels.json b/tests/SpecTests/retryable-writes/deleteOne-errorLabels.json index bff02e1f9..c14692fd1 100644 --- a/tests/SpecTests/retryable-writes/deleteOne-errorLabels.json +++ b/tests/SpecTests/retryable-writes/deleteOne-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json b/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json index 69d225759..4eab2fa29 100644 --- a/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/findOneAndDelete-errorLabels.json b/tests/SpecTests/retryable-writes/findOneAndDelete-errorLabels.json index efa62dba2..60e6e0a7b 100644 --- a/tests/SpecTests/retryable-writes/findOneAndDelete-errorLabels.json +++ b/tests/SpecTests/retryable-writes/findOneAndDelete-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json b/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json index 0785e5d03..4c1086161 100644 --- a/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json +++ b/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/findOneAndReplace-errorLabels.json b/tests/SpecTests/retryable-writes/findOneAndReplace-errorLabels.json index d9473d139..afa2f47af 100644 --- a/tests/SpecTests/retryable-writes/findOneAndReplace-errorLabels.json +++ b/tests/SpecTests/retryable-writes/findOneAndReplace-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json b/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json index 6ebe057cf..64c69e2f6 100644 --- a/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json +++ b/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/findOneAndUpdate-errorLabels.json b/tests/SpecTests/retryable-writes/findOneAndUpdate-errorLabels.json index 1926d7fa5..19b3a9e77 100644 --- a/tests/SpecTests/retryable-writes/findOneAndUpdate-errorLabels.json +++ b/tests/SpecTests/retryable-writes/findOneAndUpdate-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json b/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json index e6e369c13..9f5460499 100644 --- a/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json +++ b/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/insertMany-errorLabels.json b/tests/SpecTests/retryable-writes/insertMany-errorLabels.json index c78946e90..65fd377fa 100644 --- a/tests/SpecTests/retryable-writes/insertMany-errorLabels.json +++ b/tests/SpecTests/retryable-writes/insertMany-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/insertMany-serverErrors.json b/tests/SpecTests/retryable-writes/insertMany-serverErrors.json index 1c6ebafc2..7b45b506c 100644 --- a/tests/SpecTests/retryable-writes/insertMany-serverErrors.json +++ b/tests/SpecTests/retryable-writes/insertMany-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/insertOne-errorLabels.json b/tests/SpecTests/retryable-writes/insertOne-errorLabels.json index 9b8d13d52..d90ac5dfb 100644 --- a/tests/SpecTests/retryable-writes/insertOne-errorLabels.json +++ b/tests/SpecTests/retryable-writes/insertOne-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/insertOne-serverErrors.json b/tests/SpecTests/retryable-writes/insertOne-serverErrors.json index fda82dabb..e8571f8cf 100644 --- a/tests/SpecTests/retryable-writes/insertOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/insertOne-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/replaceOne-errorLabels.json b/tests/SpecTests/retryable-writes/replaceOne-errorLabels.json index 06867e515..6029b875d 100644 --- a/tests/SpecTests/retryable-writes/replaceOne-errorLabels.json +++ b/tests/SpecTests/retryable-writes/replaceOne-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json b/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json index af18bcf1a..7457228cd 100644 --- a/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/updateMany.json b/tests/SpecTests/retryable-writes/updateMany.json index 14288c286..46fef73e7 100644 --- a/tests/SpecTests/retryable-writes/updateMany.json +++ b/tests/SpecTests/retryable-writes/updateMany.json @@ -4,7 +4,8 @@ "minServerVersion": "3.6", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/updateOne-errorLabels.json b/tests/SpecTests/retryable-writes/updateOne-errorLabels.json index 4a6be3ffb..5bd00cde9 100644 --- a/tests/SpecTests/retryable-writes/updateOne-errorLabels.json +++ b/tests/SpecTests/retryable-writes/updateOne-errorLabels.json @@ -4,7 +4,8 @@ "minServerVersion": "4.3.1", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/retryable-writes/updateOne-serverErrors.json b/tests/SpecTests/retryable-writes/updateOne-serverErrors.json index bb442eb68..116019801 100644 --- a/tests/SpecTests/retryable-writes/updateOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/updateOne-serverErrors.json @@ -9,7 +9,8 @@ { "minServerVersion": "4.1.7", "topology": [ - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/transactions/error-labels.json b/tests/SpecTests/transactions/error-labels.json index c008a7c08..a57f216b9 100644 --- a/tests/SpecTests/transactions/error-labels.json +++ b/tests/SpecTests/transactions/error-labels.json @@ -10,7 +10,8 @@ "minServerVersion": "4.1.8", "topology": [ "sharded" - ] + ], + "serverless": "forbid" } ], "database_name": "transaction-tests", diff --git a/tests/SpecTests/transactions/mongos-pin-auto.json b/tests/SpecTests/transactions/mongos-pin-auto.json index f6ede5268..037f212f4 100644 --- a/tests/SpecTests/transactions/mongos-pin-auto.json +++ b/tests/SpecTests/transactions/mongos-pin-auto.json @@ -4,7 +4,8 @@ "minServerVersion": "4.1.8", "topology": [ "sharded" - ] + ], + "serverless": "forbid" } ], "database_name": "transaction-tests", diff --git a/tests/SpecTests/transactions/mongos-recovery-token.json b/tests/SpecTests/transactions/mongos-recovery-token.json index cd0a3c7cd..02c2002f7 100644 --- a/tests/SpecTests/transactions/mongos-recovery-token.json +++ b/tests/SpecTests/transactions/mongos-recovery-token.json @@ -4,7 +4,8 @@ "minServerVersion": "4.1.8", "topology": [ "sharded" - ] + ], + "serverless": "forbid" } ], "database_name": "transaction-tests", diff --git a/tests/SpecTests/transactions/pin-mongos.json b/tests/SpecTests/transactions/pin-mongos.json index e0f3a880b..485a3d932 100644 --- a/tests/SpecTests/transactions/pin-mongos.json +++ b/tests/SpecTests/transactions/pin-mongos.json @@ -4,7 +4,8 @@ "minServerVersion": "4.1.8", "topology": [ "sharded" - ] + ], + "serverless": "forbid" } ], "database_name": "transaction-tests", diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index ad9d54071..e35ff631a 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -90,6 +90,7 @@ public function provideCommandMonitoringTests() /** * @dataProvider provideCrudTests + * @group serverless */ public function testCrud(UnifiedTestCase $test): void { @@ -129,6 +130,7 @@ public function provideSessionsTests() /** * @dataProvider provideTransactionsTests + * @group serverless */ public function testTransactions(UnifiedTestCase $test): void { @@ -143,6 +145,7 @@ public function provideTransactionsTests() /** * @dataProvider provideVersionedApiTests * @group versioned-api + * @group serverless */ public function testVersionedApi(UnifiedTestCase $test): void { diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index e39246958..aee149d30 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -19,7 +19,9 @@ use function call_user_func; use function count; +use function filter_var; use function gc_collect_cycles; +use function getenv; use function in_array; use function is_string; use function PHPUnit\Framework\assertContainsOnly; @@ -33,6 +35,8 @@ use function strpos; use function version_compare; +use const FILTER_VALIDATE_BOOLEAN; + /** * Unified test runner. * @@ -74,7 +78,7 @@ public function __construct(string $internalClientUri) /* Atlas prohibits killAllSessions. Inspect the connection string to * determine if we should avoid calling killAllSessions(). This does * mean that lingering transactions could block test execution. */ - if (strpos($internalClientUri, self::ATLAS_TLD) !== false) { + if ($this->isServerless() || strpos($internalClientUri, self::ATLAS_TLD) !== false) { $this->allowKillAllSessions = false; } } @@ -339,8 +343,9 @@ private function isAuthenticated(): bool */ private function isServerless(): bool { - // TODO: detect serverless once PHPC-1755 is implemented - return false; + $isServerless = getenv('MONGODB_IS_SERVERLESS'); + + return $isServerless !== false ? filter_var($isServerless, FILTER_VALIDATE_BOOLEAN) : false; } /** diff --git a/tests/UnifiedSpecTests/crud/aggregate-let.json b/tests/UnifiedSpecTests/crud/aggregate-let.json index 4ce8256cb..d3b76bd65 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-let.json +++ b/tests/UnifiedSpecTests/crud/aggregate-let.json @@ -1,6 +1,6 @@ { "description": "aggregate-let", - "schemaVersion": "1.0", + "schemaVersion": "1.4", "createEntities": [ { "client": { @@ -310,7 +310,8 @@ "description": "Aggregate to collection with let option", "runOnRequirements": [ { - "minServerVersion": "5.0" + "minServerVersion": "5.0", + "serverless": "forbid" } ], "operations": [ diff --git a/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json b/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json index 9f0a9688e..e293457c1 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json +++ b/tests/UnifiedSpecTests/crud/aggregate-out-readConcern.json @@ -1,13 +1,14 @@ { "description": "aggregate-out-readConcern", - "schemaVersion": "1.0", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "4.1.0", "topologies": [ "replicaset", "sharded" - ] + ], + "serverless": "forbid" } ], "createEntities": [ From f4a6e8d84c1650a5bb086597a626edbc7f493fcf Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 7 Sep 2021 08:17:59 +0200 Subject: [PATCH 084/321] PHPLIB-716 Add PHP 8.1 to CI pipeline (#860) --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dbde407ee..e317da929 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,6 +23,7 @@ jobs: php-version: - "7.4" - "8.0" + - "8.1" mongodb-version: - "4.4" driver-version: From 7ed839a2253fc55c3ef6674a967fadfc7b9c9469 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 18 Oct 2021 18:08:31 -0400 Subject: [PATCH 085/321] PHPLIB-651: Support $merge and $out executing on secondaries (#861) Synced CRUD spec tests with mongodb/specifications@5f8f6689538a39a36186285e747d3ac2fbcb27d1 --- src/Collection.php | 19 +- src/Database.php | 19 +- src/Operation/Aggregate.php | 78 +-- .../crud/aggregate-write-readPreference.json | 457 ++++++++++++++++++ .../db-aggregate-write-readPreference.json | 443 +++++++++++++++++ 5 files changed, 975 insertions(+), 41 deletions(-) create mode 100644 tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json create mode 100644 tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json diff --git a/src/Collection.php b/src/Collection.php index f30ce8607..e6976c608 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -87,6 +87,9 @@ class Collection /** @var integer */ private static $wireVersionForReadConcernWithWriteStage = 8; + /** @var integer */ + private static $wireVersionForSecondarySupportsWriteStage = 13; + /** @var string */ private $collectionName; @@ -225,11 +228,21 @@ public function aggregate(array $pipeline, array $options = []) $options['readPreference'] = $this->readPreference; } - if ($hasWriteStage) { + $server = select_server($this->manager, $options); + + /* If a write stage is being used with a read preference (explicit or + * inherited), check that the wire version supports it. If not, force a + * primary read preference and select a new server if necessary. */ + if ( + $hasWriteStage && isset($options['readPreference']) && + ! server_supports_feature($server, self::$wireVersionForSecondarySupportsWriteStage) + ) { $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); - } - $server = select_server($this->manager, $options); + if ($server->isSecondary()) { + $server = select_server($this->manager, $options); + } + } /* MongoDB 4.2 and later supports a read concern when an $out stage is * being used, but earlier versions do not. diff --git a/src/Database.php b/src/Database.php index de5c358c6..8f050341a 100644 --- a/src/Database.php +++ b/src/Database.php @@ -64,6 +64,9 @@ class Database /** @var integer */ private static $wireVersionForReadConcernWithWriteStage = 8; + /** @var integer */ + private static $wireVersionForSecondarySupportsWriteStage = 13; + /** @var string */ private $databaseName; @@ -206,11 +209,21 @@ public function aggregate(array $pipeline, array $options = []) $options['readPreference'] = $this->readPreference; } - if ($hasWriteStage) { + $server = select_server($this->manager, $options); + + /* If a write stage is being used with a read preference (explicit or + * inherited), check that the wire version supports it. If not, force a + * primary read preference and select a new server if necessary. */ + if ( + $hasWriteStage && isset($options['readPreference']) && + ! server_supports_feature($server, self::$wireVersionForSecondarySupportsWriteStage) + ) { $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); - } - $server = select_server($this->manager, $options); + if ($server->isSecondary()) { + $server = select_server($this->manager, $options); + } + } /* MongoDB 4.2 and later supports a read concern when an $out stage is * being used, but earlier versions do not. diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 5cbe7efac..25c1badfa 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -19,6 +19,7 @@ use ArrayIterator; use MongoDB\Driver\Command; +use MongoDB\Driver\Cursor; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; @@ -75,6 +76,12 @@ class Aggregate implements Executable, Explainable /** @var array */ private $options; + /** @var bool */ + private $isExplain; + + /** @var bool */ + private $isWrite; + /** * Constructs an aggregate command. * @@ -253,8 +260,19 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr unset($options['writeConcern']); } - if (! empty($options['explain'])) { + $this->isExplain = ! empty($options['explain']); + $this->isWrite = is_last_pipeline_operator_write($pipeline) && ! $this->isExplain; + + // Explain does not use a cursor + if ($this->isExplain) { $options['useCursor'] = false; + unset($options['batchSize']); + } + + /* Ignore batchSize for writes, since no documents are returned and a + * batchSize of zero could prevent the pipeline from executing. */ + if ($this->isWrite) { + unset($options['batchSize']); } $this->databaseName = (string) $databaseName; @@ -298,20 +316,14 @@ public function execute(Server $server) } } - $hasExplain = ! empty($this->options['explain']); - $hasWriteStage = $this->hasWriteStage(); - $command = new Command( - $this->createCommandDocument($server, $hasWriteStage), + $this->createCommandDocument($server), $this->createCommandOptions() ); - $options = $this->createOptions($hasWriteStage, $hasExplain); - $cursor = $hasWriteStage && ! $hasExplain - ? $server->executeReadWriteCommand($this->databaseName, $command, $options) - : $server->executeReadCommand($this->databaseName, $command, $options); + $cursor = $this->executeCommand($server, $command); - if ($this->options['useCursor'] || $hasExplain) { + if ($this->options['useCursor'] || $this->isExplain) { if (isset($this->options['typeMap'])) { $cursor->setTypeMap($this->options['typeMap']); } @@ -341,10 +353,10 @@ public function execute(Server $server) */ public function getCommandDocument(Server $server) { - return $this->createCommandDocument($server, $this->hasWriteStage()); + return $this->createCommandDocument($server); } - private function createCommandDocument(Server $server, bool $hasWriteStage): array + private function createCommandDocument(Server $server): array { $cmd = [ 'aggregate' => $this->collectionName ?? 1, @@ -377,10 +389,7 @@ private function createCommandDocument(Server $server, bool $hasWriteStage): arr } if ($this->options['useCursor']) { - /* Ignore batchSize if pipeline includes an $out or $merge stage, as - * no documents will be returned and sending a batchSize of zero - * could prevent the pipeline from executing at all. */ - $cmd['cursor'] = isset($this->options["batchSize"]) && ! $hasWriteStage + $cmd['cursor'] = isset($this->options["batchSize"]) ? ['batchSize' => $this->options["batchSize"]] : new stdClass(); } @@ -400,39 +409,38 @@ private function createCommandOptions(): array } /** - * Create options for executing the command. + * Execute the aggregate command using the appropriate Server method. * + * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php * @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php * @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php - * @param boolean $hasWriteStage - * @param boolean $hasExplain - * @return array */ - private function createOptions($hasWriteStage, $hasExplain) + private function executeCommand(Server $server, Command $command): Cursor { $options = []; - if (isset($this->options['readConcern'])) { - $options['readConcern'] = $this->options['readConcern']; + foreach (['readConcern', 'readPreference', 'session'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = $this->options[$option]; + } } - if (! $hasWriteStage && isset($this->options['readPreference'])) { - $options['readPreference'] = $this->options['readPreference']; + if ($this->isWrite && isset($this->options['writeConcern'])) { + $options['writeConcern'] = $this->options['writeConcern']; } - if (isset($this->options['session'])) { - $options['session'] = $this->options['session']; + if (! $this->isWrite) { + return $server->executeReadCommand($this->databaseName, $command, $options); } - if ($hasWriteStage && ! $hasExplain && isset($this->options['writeConcern'])) { - $options['writeConcern'] = $this->options['writeConcern']; + /* Server::executeReadWriteCommand() does not support a "readPreference" + * option, so fall back to executeCommand(). This means that libmongoc + * will not apply any client-level options (e.g. writeConcern), but that + * should not be an issue as PHPLIB handles inheritance on its own. */ + if (isset($options['readPreference'])) { + return $server->executeCommand($this->databaseName, $command, $options); } - return $options; - } - - private function hasWriteStage(): bool - { - return is_last_pipeline_operator_write($this->pipeline); + return $server->executeReadWriteCommand($this->databaseName, $command, $options); } } diff --git a/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json b/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json new file mode 100644 index 000000000..2bb1945ba --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json @@ -0,0 +1,457 @@ +{ + "description": "aggregate-write-readPreference", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ] + } + ], + "_yamlAnchors": { + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + }, + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "uriOptions": { + "readConcernLevel": "local", + "w": 1 + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "readPreference": { + "mode": "secondaryPreferred", + "maxStalenessSeconds": 600 + } + } + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + }, + { + "collectionName": "coll1", + "databaseName": "db0", + "documents": [] + } + ], + "tests": [ + { + "description": "Aggregate with $out includes read preference for 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$out": "coll1" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$out": "coll1" + } + ], + "$readPreference": { + "mode": "secondaryPreferred", + "maxStalenessSeconds": 600 + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll1", + "databaseName": "db0", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $out omits read preference for pre-5.0 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$out": "coll1" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$out": "coll1" + } + ], + "$readPreference": { + "$$exists": false + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll1", + "databaseName": "db0", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $merge includes read preference for 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$merge": { + "into": "coll1" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$merge": { + "into": "coll1" + } + } + ], + "$readPreference": { + "mode": "secondaryPreferred", + "maxStalenessSeconds": 600 + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll1", + "databaseName": "db0", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + }, + { + "description": "Aggregate with $merge omits read preference for pre-5.0 server", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$merge": { + "into": "coll1" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$sort": { + "x": 1 + } + }, + { + "$merge": { + "into": "coll1" + } + } + ], + "$readPreference": { + "$$exists": false + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll1", + "databaseName": "db0", + "documents": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json b/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json new file mode 100644 index 000000000..a89e79500 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json @@ -0,0 +1,443 @@ +{ + "description": "db-aggregate-write-readPreference", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "topologies": [ + "replicaset" + ], + "serverless": "forbid" + } + ], + "_yamlAnchors": { + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + }, + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "uriOptions": { + "readConcernLevel": "local", + "w": 1 + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "db0", + "databaseOptions": { + "readPreference": { + "mode": "secondaryPreferred", + "maxStalenessSeconds": 600 + } + } + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [] + } + ], + "tests": [ + { + "description": "Database-level aggregate with $out includes read preference for 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "database0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll0" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll0" + } + ], + "$readPreference": { + "mode": "secondaryPreferred", + "maxStalenessSeconds": 600 + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Database-level aggregate with $out omits read preference for pre-5.0 server", + "runOnRequirements": [ + { + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "object": "database0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll0" + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$out": "coll0" + } + ], + "$readPreference": { + "$$exists": false + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Database-level aggregate with $merge includes read preference for 5.0+ server", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "database0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$merge": { + "into": "coll0" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$merge": { + "into": "coll0" + } + } + ], + "$readPreference": { + "mode": "secondaryPreferred", + "maxStalenessSeconds": 600 + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Database-level aggregate with $merge omits read preference for pre-5.0 server", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "object": "database0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$merge": { + "into": "coll0" + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "pipeline": [ + { + "$listLocalSessions": {} + }, + { + "$limit": 1 + }, + { + "$addFields": { + "_id": 1 + } + }, + { + "$project": { + "_id": 1 + } + }, + { + "$merge": { + "into": "coll0" + } + } + ], + "$readPreference": { + "$$exists": false + }, + "readConcern": { + "level": "local" + }, + "writeConcern": { + "w": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "db0", + "documents": [ + { + "_id": 1 + } + ] + } + ] + } + ] +} From c4302b943cae7537a16e2f2668f33abc9fa28b72 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 13 Oct 2021 10:32:04 -0400 Subject: [PATCH 086/321] PHPLIB-671: Load balancer testing Add load balancer task to Evergreen. This cleans up some unused variables in run-tests.sh and copies over SSL URI handling from PHPC (needed since LB appears to be the first task using SSL). Sync all spec tests. Synced with mongodb/specifications@b508f6d2a1819882d40c4e7e73b95fc8ae3bdfe5 Added skips for some CSFLE and command monitoring tests, which replaces a previous manual edit to azureKMS.json. Various test suite fixes for load balancers and/or sharded clusters. --- .evergreen/config.yml | 44 +- .evergreen/run-tests.sh | 32 +- tests/Collection/CollectionFunctionalTest.php | 4 +- tests/FunctionalTestCase.php | 25 +- .../RenameCollectionFunctionalTest.php | 7 +- tests/Operation/WatchFunctionalTest.php | 4 + .../ClientSideEncryptionSpecTest.php | 11 + tests/SpecTests/FunctionalTestCase.php | 4 +- tests/SpecTests/RetryableWritesSpecTest.php | 2 +- tests/SpecTests/TransactionsSpecTest.php | 14 +- tests/SpecTests/atlas_data_lake/getMore.json | 2 +- .../atlas_data_lake/listCollections.json | 2 +- .../atlas_data_lake/listDatabases.json | 2 +- .../SpecTests/atlas_data_lake/runCommand.json | 2 +- tests/SpecTests/change-streams/README.rst | 203 --- .../change-streams/change-streams-errors.json | 6 +- ...n => change-streams-resume-allowlist.json} | 9 +- .../change-streams-resume-errorLabels.json | 60 +- .../tests/aggregate.json | 24 - .../tests/awsTemporary.json | 225 +++ .../tests/azureKMS.json | 13 - .../client-side-encryption/tests/basic.json | 24 - .../client-side-encryption/tests/bulk.json | 12 - .../client-side-encryption/tests/count.json | 12 - .../tests/countDocuments.json | 12 - .../client-side-encryption/tests/delete.json | 24 - .../tests/distinct.json | 12 - .../client-side-encryption/tests/explain.json | 12 - .../client-side-encryption/tests/find.json | 24 - .../tests/findOneAndDelete.json | 12 - .../tests/findOneAndReplace.json | 12 - .../tests/findOneAndUpdate.json | 12 - .../client-side-encryption/tests/gcpKMS.json | 12 - .../client-side-encryption/tests/getMore.json | 12 - .../client-side-encryption/tests/insert.json | 24 - .../tests/keyAltName.json | 12 - .../tests/localKMS.json | 12 - .../tests/localSchema.json | 12 - .../tests/missingKey.json | 12 - .../tests/replaceOne.json | 12 - .../client-side-encryption/tests/types.json | 96 - .../tests/updateMany.json | 12 - .../tests/updateOne.json | 12 - tests/UnifiedSpecTests/EventObserver.php | 54 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 48 + tests/UnifiedSpecTests/UnifiedTestRunner.php | 4 +- .../pre-42-server-connection-id.json | 101 + .../server-connection-id.json | 101 + .../load-balancers/cursors.json | 1238 +++++++++++++ .../load-balancers/event-monitoring.json | 184 ++ .../lb-connection-establishment.json | 58 + .../non-lb-connection-establishment.json | 92 + .../load-balancers/sdam-error-handling.json | 514 ++++++ .../load-balancers/server-selection.json | 82 + .../load-balancers/transactions.json | 1621 +++++++++++++++++ .../load-balancers/wait-queue-timeouts.json | 153 ++ .../UnifiedSpecTests/valid-pass/poc-crud.json | 3 +- 57 files changed, 4647 insertions(+), 697 deletions(-) delete mode 100644 tests/SpecTests/change-streams/README.rst rename tests/SpecTests/change-streams/{change-streams-resume-whitelist.json => change-streams-resume-allowlist.json} (99%) create mode 100644 tests/SpecTests/client-side-encryption/tests/awsTemporary.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/pre-42-server-connection-id.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/server-connection-id.json create mode 100644 tests/UnifiedSpecTests/load-balancers/cursors.json create mode 100644 tests/UnifiedSpecTests/load-balancers/event-monitoring.json create mode 100644 tests/UnifiedSpecTests/load-balancers/lb-connection-establishment.json create mode 100644 tests/UnifiedSpecTests/load-balancers/non-lb-connection-establishment.json create mode 100644 tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json create mode 100644 tests/UnifiedSpecTests/load-balancers/server-selection.json create mode 100644 tests/UnifiedSpecTests/load-balancers/transactions.json create mode 100644 tests/UnifiedSpecTests/load-balancers/wait-queue-timeouts.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 877faf0ef..69c15d429 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -246,7 +246,7 @@ functions: export GCP_EMAIL="${client_side_encryption_gcp_email}" export GCP_PRIVATEKEY="${client_side_encryption_gcp_privatekey}" export PATH="${PHP_PATH}/bin:$PATH" - API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + MOCK_SERVICE_ID=${MOCK_SERVICE_ID} API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run atlas data lake test": - command: shell.exec @@ -323,6 +323,24 @@ functions: params: file: src/php-expansion.yml + "start load balancer": + - command: shell.exec + params: + script: | + MONGODB_URI="${MONGODB_URI}" ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh start + - command: expansions.update + params: + file: lb-expansion.yml + + "stop load balancer": + - command: shell.exec + params: + script: | + # Only run if a load balancer was started + if [ -n "${SINGLE_MONGOS_LB_URI}" ]; then + ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop + fi + pre: - func: "fetch source" - func: "prepare resources" @@ -336,6 +354,7 @@ post: # - func: "upload working dir" - func: "upload mo artifacts" - func: "upload test results" + - func: "stop load balancer" - func: "stop mongo-orchestration" - func: "cleanup" @@ -432,6 +451,23 @@ tasks: PROJECT: "mongo-php-library" - func: "run serverless tests" - func: "delete serverless instance" + + - name: "test-loadBalanced" + tags: ["loadbalanced"] + commands: + - func: "bootstrap mongo-orchestration" + vars: + TOPOLOGY: "sharded_cluster" + SSL: "yes" + - func: "start load balancer" + - func: "run tests" + vars: + # Testing with HAProxy requires service ID mocking + MOCK_SERVICE_ID: 1 + # Note: loadBalanced=true should already be appended to SINGLE_MONGOS_LB_URI + MONGODB_URI: "${SINGLE_MONGOS_LB_URI}" + SSL: "yes" + # Note: "stop load balancer" will be called from "post" # }}} @@ -693,3 +729,9 @@ buildvariants: run_on: rhel70 tasks: - .serverless + +- matrix_name: "test-loadBalanced" + matrix_spec: { "os-php7": "debian92-test", "php-versions": "7.3", "versions": ["5.0", "latest"], "driver-versions": "latest-dev" } + display_name: "Load balanced - ${versions}" + tasks: + - name: "test-loadBalanced" diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 5cf1978cd..bbb8a1f44 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -2,18 +2,17 @@ set -o errexit # Exit the script with error if any of the commands fail # Supported/used environment variables: -# AUTH Set to enable authentication. Defaults to "noauth" -# SSL Set to enable SSL. Defaults to "nossl" -# MONGODB_URI Set the suggested connection MONGODB_URI (including credentials and topology info) -# MARCH Machine Architecture. Defaults to lowercase uname -m +# SSL Set to "yes" to enable SSL. Defaults to "nossl" +# MONGODB_URI Set the suggested connection MONGODB_URI (including credentials and topology info) +# API_VERSION Optional API_VERSION environment variable for run-tests.php +# IS_MATRIX_TESTING Set to "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked. +# MOCK_SERVICE_ID Set to "1" to enable service ID mocking for load balancers. Defaults to empty string. - -AUTH=${AUTH:-noauth} SSL=${SSL:-nossl} MONGODB_URI=${MONGODB_URI:-} -TESTS=${TESTS:-} API_VERSION=${API_VERSION:-} IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} +MOCK_SERVICE_ID=${MOCK_SERVICE_ID:-} # For matrix testing, we have to determine the correct driver version if [ "${IS_MATRIX_TESTING}" = "true" ]; then @@ -44,10 +43,23 @@ if [ "${IS_MATRIX_TESTING}" = "true" ]; then . $DIR/install-dependencies.sh fi -OS=$(uname -s | tr '[:upper:]' '[:lower:]') -[ -z "$MARCH" ] && MARCH=$(uname -m | tr '[:upper:]' '[:lower:]') +# For load balancer testing, we need to enable service ID mocking +if [ "${MOCK_SERVICE_ID}" = "1" ]; then + PHPUNIT_OPTS="${PHPUNIT_OPTS} -d mongodb.mock_service_id=1" +fi + +# Determine if MONGODB_URI already has a query string +SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat) + +if [ "$SSL" = "yes" ]; then + if [ -z "$SUFFIX" ]; then + MONGODB_URI="${MONGODB_URI}/?ssl=true&sslallowinvalidcertificates=true" + else + MONGODB_URI="${MONGODB_URI}&ssl=true&sslallowinvalidcertificates=true" + fi +fi -echo "Running tests with $AUTH and $SSL, connecting to: $MONGODB_URI" +echo "Running tests with URI: $MONGODB_URI" # Disable failing PHPUnit due to deprecations export SYMFONY_DEPRECATIONS_HELPER=999999 diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index fd8018e1d..2c5383116 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -356,8 +356,8 @@ public function testRenameToDifferentDatabase(): void $toDatabase = new Database($this->manager, $toDatabaseName); /* When renaming an unsharded collection, mongos requires the source - * and target database to both exist on the primary shard. In practice, this - * means we need to create the target database explicitly. + * and target database to both exist on the primary shard. In practice, + * this means we need to create the target database explicitly. * See: https://docs.mongodb.com/manual/reference/command/renameCollection/#unsharded-collections */ if ($this->isShardedCluster()) { diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 3a70f34ff..00a1b712e 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -390,11 +390,21 @@ protected function getServerStorageEngine(?ReadPreference $readPreference = null throw new UnexpectedValueException('Could not determine server storage engine'); } + protected function isLoadBalanced() + { + return $this->getPrimaryServer()->getType() == Server::TYPE_LOAD_BALANCER; + } + protected function isReplicaSet() { return $this->getPrimaryServer()->getType() == Server::TYPE_RS_PRIMARY; } + protected function isMongos() + { + return $this->getPrimaryServer()->getType() == Server::TYPE_MONGOS; + } + /** * Return whether serverless (i.e. proxy as mongos) is being utilized. */ @@ -407,7 +417,18 @@ protected static function isServerless(): bool protected function isShardedCluster() { - return $this->getPrimaryServer()->getType() == Server::TYPE_MONGOS; + $type = $this->getPrimaryServer()->getType(); + + if ($type == Server::TYPE_MONGOS) { + return true; + } + + // Assume that load balancers are properly configured and front mongos + if ($type == Server::TYPE_LOAD_BALANCER) { + return true; + } + + return false; } protected function isShardedClusterUsingReplicasets() @@ -436,6 +457,7 @@ protected function skipIfChangeStreamIsNotSupported(): void { switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_MONGOS: + case Server::TYPE_LOAD_BALANCER: if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('$changeStream is only supported on MongoDB 3.6 or higher'); } @@ -462,6 +484,7 @@ protected function skipIfCausalConsistencyIsNotSupported(): void { switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_MONGOS: + case Server::TYPE_LOAD_BALANCER: if (version_compare($this->getServerVersion(), '3.6.0', '<')) { $this->markTestSkipped('Causal Consistency is only supported on MongoDB 3.6 or higher'); } diff --git a/tests/Operation/RenameCollectionFunctionalTest.php b/tests/Operation/RenameCollectionFunctionalTest.php index c14969681..6df2f16ff 100644 --- a/tests/Operation/RenameCollectionFunctionalTest.php +++ b/tests/Operation/RenameCollectionFunctionalTest.php @@ -106,7 +106,12 @@ public function testRenameCollectionExistingTarget(): void $this->assertEquals(1, $writeResult->getInsertedCount()); $this->expectException(CommandException::class); - $this->expectExceptionCode(self::$errorCodeNamespaceExists); + + // mongos returns an inconsistent error code (see: SERVER-60632) + if (! $this->isShardedCluster()) { + $this->expectExceptionCode(self::$errorCodeNamespaceExists); + } + $operation = new RenameCollection( $this->getDatabaseName(), $this->getCollectionName(), diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php index 2d64cf568..e55be49d5 100644 --- a/tests/Operation/WatchFunctionalTest.php +++ b/tests/Operation/WatchFunctionalTest.php @@ -1178,6 +1178,10 @@ function (array $event) use (&$sessionAfterResume, &$commands): void { public function testSessionFreed(): void { + if ($this->isShardedCluster() && version_compare($this->getServerVersion(), '5.1.0', '>=')) { + $this->markTestSkipped('mongos still reports non-zero cursor ID for invalidated change stream (SERVER-60764)'); + } + $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions); $changeStream = $operation->execute($this->getPrimaryServer()); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 8b9115467..00fbee5a5 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -42,6 +42,13 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase { public const LOCAL_MASTERKEY = 'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk'; + /** @var array */ + private static $incompleteTests = [ + 'awsTemporary: Insert a document with auto encryption using the AWS provider with temporary credentials' => 'Not yet implemented (PHPC-1751)', + 'awsTemporary: Insert with invalid temporary credentials' => 'Not yet implemented (PHPC-1751)', + 'azureKMS: Insert a document with auto encryption using Azure KMS provider' => 'RHEL platform is missing Azure root certificate (PHPLIB-619)', + ]; + public function setUp(): void { parent::setUp(); @@ -74,6 +81,10 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual */ public function testClientSideEncryption(stdClass $test, ?array $runOn = null, array $data, ?array $keyVaultData = null, $jsonSchema = null, ?string $databaseName = null, ?string $collectionName = null): void { + if (isset(self::$incompleteTests[$this->dataDescription()])) { + $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); + } + if (isset($runOn)) { $this->checkServerRequirements($runOn); } diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index d9738c568..8dc12c172 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -29,6 +29,7 @@ class FunctionalTestCase extends BaseFunctionalTestCase public const TOPOLOGY_SINGLE = 'single'; public const TOPOLOGY_REPLICASET = 'replicaset'; public const TOPOLOGY_SHARDED = 'sharded'; + public const TOPOLOGY_LOAD_BALANCED = 'load-balanced'; public const SERVERLESS_ALLOW = 'allow'; public const SERVERLESS_FORBID = 'forbid'; @@ -265,6 +266,7 @@ private function getTopology(): string Server::TYPE_STANDALONE => self::TOPOLOGY_SINGLE, Server::TYPE_RS_PRIMARY => self::TOPOLOGY_REPLICASET, Server::TYPE_MONGOS => self::TOPOLOGY_SHARDED, + Server::TYPE_LOAD_BALANCER => self::TOPOLOGY_LOAD_BALANCED, ]; $primaryType = $this->getPrimaryServer()->getType(); @@ -273,7 +275,7 @@ private function getTopology(): string return $topologyTypeMap[$primaryType]; } - throw new UnexpectedValueException(sprintf('Cannot find topology for primary of type "%s".', $primaryType)); + throw new UnexpectedValueException(sprintf('Cannot find topology for primary of type "%d".', $primaryType)); } private function isServerlessRequirementSatisfied(?string $serverlessMode): bool diff --git a/tests/SpecTests/RetryableWritesSpecTest.php b/tests/SpecTests/RetryableWritesSpecTest.php index aa9f9083d..a709806db 100644 --- a/tests/SpecTests/RetryableWritesSpecTest.php +++ b/tests/SpecTests/RetryableWritesSpecTest.php @@ -30,7 +30,7 @@ public function testRetryableWrites(stdClass $test, ?array $runOn = null, array $this->markTestSkipped('Transaction numbers are only allowed on a replica set member or mongos (PHPC-1415)'); } - $useMultipleMongoses = isset($test->useMultipleMongoses) && $test->useMultipleMongoses && $this->isShardedCluster(); + $useMultipleMongoses = isset($test->useMultipleMongoses) && $test->useMultipleMongoses && $this->isMongos(); if (isset($runOn)) { $this->checkServerRequirements($runOn); diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 165f3c255..b50519e21 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -152,7 +152,7 @@ private function runTransactionTest(stdClass $test, ?array $runOn = null, array $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); } - $useMultipleMongoses = isset($test->useMultipleMongoses) && $test->useMultipleMongoses && $this->isShardedCluster(); + $useMultipleMongoses = isset($test->useMultipleMongoses) && $test->useMultipleMongoses && $this->isMongos(); if (isset($runOn)) { $this->checkServerRequirements($runOn); @@ -229,8 +229,10 @@ private function provideTests(string $dir): array */ public function testStartingNewTransactionOnPinnedSessionUnpinsSession(): void { - if (! $this->isShardedClusterUsingReplicasets()) { - $this->markTestSkipped('Mongos pinning tests can only run on sharded clusters using replica sets'); + $this->skipIfTransactionsAreNotSupported(); + + if (! $this->isMongos()) { + $this->markTestSkipped('Pinning tests require mongos'); } $client = self::createTestClient($this->getUri(true)); @@ -267,8 +269,10 @@ public function testStartingNewTransactionOnPinnedSessionUnpinsSession(): void */ public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession(): void { - if (! $this->isShardedClusterUsingReplicasets()) { - $this->markTestSkipped('Mongos pinning tests can only run on sharded clusters using replica sets'); + $this->skipIfTransactionsAreNotSupported(); + + if (! $this->isMongos()) { + $this->markTestSkipped('Pinning tests require mongos'); } $client = self::createTestClient($this->getUri(true)); diff --git a/tests/SpecTests/atlas_data_lake/getMore.json b/tests/SpecTests/atlas_data_lake/getMore.json index fa1deab4f..e2e1d4788 100644 --- a/tests/SpecTests/atlas_data_lake/getMore.json +++ b/tests/SpecTests/atlas_data_lake/getMore.json @@ -54,4 +54,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/tests/SpecTests/atlas_data_lake/listCollections.json b/tests/SpecTests/atlas_data_lake/listCollections.json index 8d8a8f6c1..e419f7b3e 100644 --- a/tests/SpecTests/atlas_data_lake/listCollections.json +++ b/tests/SpecTests/atlas_data_lake/listCollections.json @@ -22,4 +22,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/tests/SpecTests/atlas_data_lake/listDatabases.json b/tests/SpecTests/atlas_data_lake/listDatabases.json index f8ec9a0bf..6458148e4 100644 --- a/tests/SpecTests/atlas_data_lake/listDatabases.json +++ b/tests/SpecTests/atlas_data_lake/listDatabases.json @@ -21,4 +21,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/tests/SpecTests/atlas_data_lake/runCommand.json b/tests/SpecTests/atlas_data_lake/runCommand.json index f72e863ba..d81ff1a64 100644 --- a/tests/SpecTests/atlas_data_lake/runCommand.json +++ b/tests/SpecTests/atlas_data_lake/runCommand.json @@ -28,4 +28,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/tests/SpecTests/change-streams/README.rst b/tests/SpecTests/change-streams/README.rst deleted file mode 100644 index 8472d1f6c..000000000 --- a/tests/SpecTests/change-streams/README.rst +++ /dev/null @@ -1,203 +0,0 @@ -.. role:: javascript(code) - :language: javascript - -============== -Change Streams -============== - -.. contents:: - --------- - -Introduction -============ - -The YAML and JSON files in this directory are platform-independent tests that -drivers can use to prove their conformance to the Change Streams Spec. - -Several prose tests, which are not easily expressed in YAML, are also presented -in this file. Those tests will need to be manually implemented by each driver. - -Spec Test Format -================ - -Each YAML file has the following keys: - -- ``database_name``: The default database -- ``collection_name``: The default collection -- ``database2_name``: Another database -- ``collection2_name``: Another collection -- ``tests``: An array of tests that are to be run independently of each other. - Each test will have some of the following fields: - - - ``description``: The name of the test. - - ``minServerVersion``: The minimum server version to run this test against. If not present, assume there is no minimum server version. - - ``maxServerVersion``: Reserved for later use - - ``failPoint``(optional): The configureFailPoint command document to run to configure a fail point on the primary server. - - ``target``: The entity on which to run the change stream. Valid values are: - - - ``collection``: Watch changes on collection ``database_name.collection_name`` - - ``database``: Watch changes on database ``database_name`` - - ``client``: Watch changes on entire clusters - - ``topology``: An array of server topologies against which to run the test. - Valid topologies are ``single``, ``replicaset``, and ``sharded``. - - ``changeStreamPipeline``: An array of additional aggregation pipeline stages to add to the change stream - - ``changeStreamOptions``: Additional options to add to the changeStream - - ``operations``: Array of documents, each describing an operation. Each document has the following fields: - - - ``database``: Database against which to run the operation - - ``collection``: Collection against which to run the operation - - ``name``: Name of the command to run - - ``arguments`` (optional): Object of arguments for the command (ex: document to insert) - - - ``expectations``: Optional list of command-started events in Extended JSON format - - ``result``: Document with ONE of the following fields: - - - ``error``: Describes an error received during the test - - ``success``: An Extended JSON array of documents expected to be received from the changeStream - -Spec Test Match Function -======================== - -The definition of MATCH or MATCHES in the Spec Test Runner is as follows: - -- MATCH takes two values, ``expected`` and ``actual`` -- Notation is "Assert [actual] MATCHES [expected] -- Assertion passes if ``expected`` is a subset of ``actual``, with the values ``42`` and ``"42"`` acting as placeholders for "any value" - -Pseudocode implementation of ``actual`` MATCHES ``expected``: - -:: - - If expected is "42" or 42: - Assert that actual exists (is not null or undefined) - Else: - Assert that actual is of the same JSON type as expected - If expected is a JSON array: - For every idx/value in expected: - Assert that actual[idx] MATCHES value - Else if expected is a JSON object: - For every key/value in expected - Assert that actual[key] MATCHES value - Else: - Assert that expected equals actual - -The expected values for ``result.success`` and ``expectations`` are written in Extended JSON. Drivers may adopt any of the following approaches to comparisons, as long as they are consistent: - -- Convert ``actual`` to Extended JSON and compare to ``expected`` -- Convert ``expected`` and ``actual`` to BSON, and compare them -- Convert ``expected`` and ``actual`` to native equivalents of JSON, and compare them - -Spec Test Runner -================ - -Before running the tests - -- Create a MongoClient ``globalClient``, and connect to the server - -For each YAML file, for each element in ``tests``: - -- If ``topology`` does not include the topology of the server instance(s), skip this test. -- Use ``globalClient`` to - - - Drop the database ``database_name`` - - Drop the database ``database2_name`` - - Create the database ``database_name`` and the collection ``database_name.collection_name`` - - Create the database ``database2_name`` and the collection ``database2_name.collection2_name`` - - If the the ``failPoint`` field is present, configure the fail point on the primary server. See - `Server Fail Point <../../transactions/tests#server-fail-point>`_ in the - Transactions spec test documentation for more information. - -- Create a new MongoClient ``client`` -- Begin monitoring all APM events for ``client``. (If the driver uses global listeners, filter out all events that do not originate with ``client``). Filter out any "internal" commands (e.g. ``isMaster``) -- Using ``client``, create a changeStream ``changeStream`` against the specified ``target``. Use ``changeStreamPipeline`` and ``changeStreamOptions`` if they are non-empty -- Using ``globalClient``, run every operation in ``operations`` in serial against the server -- Wait until either: - - - An error occurs - - All operations have been successful AND the changeStream has received as many changes as there are in ``result.success`` - -- Close ``changeStream`` -- If there was an error: - - - Assert that an error was expected for the test. - - Assert that the error MATCHES ``result.error`` - -- Else: - - - Assert that no error was expected for the test - - Assert that the changes received from ``changeStream`` MATCH the results in ``result.success`` - -- If there are any ``expectations`` - - - For each (``expected``, ``idx``) in ``expectations`` - - - Assert that ``actual[idx]`` MATCHES ``expected`` - -- Close the MongoClient ``client`` - -After running all tests - -- Close the MongoClient ``globalClient`` -- Drop database ``database_name`` -- Drop database ``database2_name`` - - -Prose Tests -=========== - -The following tests have not yet been automated, but MUST still be tested - -#. ``ChangeStream`` must continuously track the last seen ``resumeToken`` -#. ``ChangeStream`` will throw an exception if the server response is missing the resume token (if wire version is < 8, this is a driver-side error; for 8+, this is a server-side error) -#. ``ChangeStream`` will automatically resume one time on a resumable error (including `not master`) with the initial pipeline and options, except for the addition/update of a ``resumeToken``. -#. ``ChangeStream`` will not attempt to resume on any error encountered while executing an ``aggregate`` command. -#. ``ChangeStream`` will not attempt to resume after encountering error code 11601 (Interrupted), 136 (CappedPositionLost), or 237 (CursorKilled) while executing a ``getMore`` command. -#. ``ChangeStream`` will perform server selection before attempting to resume, using initial ``readPreference`` -#. Ensure that a cursor returned from an aggregate command with a cursor id and an initial empty batch is not closed on the driver side. -#. The ``killCursors`` command sent during the "Resume Process" must not be allowed to throw an exception. -#. ``$changeStream`` stage for ``ChangeStream`` against a server ``>=4.0`` and ``<4.0.7`` that has not received any results yet MUST include a ``startAtOperationTime`` option when resuming a changestream. -#. ``ChangeStream`` will resume after a ``killCursors`` command is issued for its child cursor. -#. - For a ``ChangeStream`` under these conditions: - - Running against a server ``>=4.0.7``. - - The batch is empty or has been iterated to the last document. - - Expected result: - - ``getResumeToken`` must return the ``postBatchResumeToken`` from the current command response. -#. - For a ``ChangeStream`` under these conditions: - - Running against a server ``<4.0.7``. - - The batch is empty or has been iterated to the last document. - - Expected result: - - ``getResumeToken`` must return the ``_id`` of the last document returned if one exists. - - ``getResumeToken`` must return ``startAfter`` from the initial aggregate if the option was specified. - - ``getResumeToken`` must return ``resumeAfter`` from the initial aggregate if the option was specified. - - If neither the ``startAfter`` nor ``resumeAfter`` options were specified, the ``getResumeToken`` result must be empty. -#. - For a ``ChangeStream`` under these conditions: - - The batch is not empty. - - The batch has been iterated up to but not including the last element. - - Expected result: - - ``getResumeToken`` must return the ``_id`` of the previous document returned. -#. - For a ``ChangeStream`` under these conditions: - - The batch is not empty. - - The batch hasn’t been iterated at all. - - Only the initial ``aggregate`` command has been executed. - - Expected result: - - ``getResumeToken`` must return ``startAfter`` from the initial aggregate if the option was specified. - - ``getResumeToken`` must return ``resumeAfter`` from the initial aggregate if the option was specified. - - If neither the ``startAfter`` nor ``resumeAfter`` options were specified, the ``getResumeToken`` result must be empty. -#. - For a ``ChangeStream`` under these conditions: - - Running against a server ``>=4.0.7``. - - The batch is not empty. - - The batch hasn’t been iterated at all. - - The stream has iterated beyond a previous batch and a ``getMore`` command has just been executed. - - Expected result: - - ``getResumeToken`` must return the ``postBatchResumeToken`` from the previous command response. -#. - For a ``ChangeStream`` under these conditions: - - Running against a server ``<4.0.7``. - - The batch is not empty. - - The batch hasn’t been iterated at all. - - The stream has iterated beyond a previous batch and a ``getMore`` command has just been executed. - - Expected result: - - ``getResumeToken`` must return the ``_id`` of the previous document returned if one exists. - - ``getResumeToken`` must return ``startAfter`` from the initial aggregate if the option was specified. - - ``getResumeToken`` must return ``resumeAfter`` from the initial aggregate if the option was specified. - - If neither the ``startAfter`` nor ``resumeAfter`` options were specified, the ``getResumeToken`` result must be empty. \ No newline at end of file diff --git a/tests/SpecTests/change-streams/change-streams-errors.json b/tests/SpecTests/change-streams/change-streams-errors.json index f0ae14ebc..7b3fa8068 100644 --- a/tests/SpecTests/change-streams/change-streams-errors.json +++ b/tests/SpecTests/change-streams/change-streams-errors.json @@ -78,7 +78,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [ { @@ -125,7 +126,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, diff --git a/tests/SpecTests/change-streams/change-streams-resume-whitelist.json b/tests/SpecTests/change-streams/change-streams-resume-allowlist.json similarity index 99% rename from tests/SpecTests/change-streams/change-streams-resume-whitelist.json rename to tests/SpecTests/change-streams/change-streams-resume-allowlist.json index 39f883ee5..baffc8fba 100644 --- a/tests/SpecTests/change-streams/change-streams-resume-whitelist.json +++ b/tests/SpecTests/change-streams/change-streams-resume-allowlist.json @@ -20,7 +20,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -777,7 +778,7 @@ } }, { - "description": "change stream resumes after NotMaster", + "description": "change stream resumes after NotWritablePrimary", "minServerVersion": "4.2", "maxServerVersion": "4.2.99", "failPoint": { @@ -1068,7 +1069,7 @@ } }, { - "description": "change stream resumes after NotMasterNoSlaveOk", + "description": "change stream resumes after NotPrimaryNoSecondaryOk", "minServerVersion": "4.2", "maxServerVersion": "4.2.99", "failPoint": { @@ -1165,7 +1166,7 @@ } }, { - "description": "change stream resumes after NotMasterOrSecondary", + "description": "change stream resumes after NotPrimaryOrSecondary", "minServerVersion": "4.2", "maxServerVersion": "4.2.99", "failPoint": { diff --git a/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json b/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json index cf8957b21..2bac61d3b 100644 --- a/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json +++ b/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json @@ -18,7 +18,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -111,7 +112,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -204,7 +206,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -297,7 +300,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -390,7 +394,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -483,7 +488,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -576,7 +582,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -654,7 +661,7 @@ } }, { - "description": "change stream resumes after NotMaster", + "description": "change stream resumes after NotWritablePrimary", "minServerVersion": "4.3.1", "failPoint": { "configureFailPoint": "failGetMoreAfterCursorCheckout", @@ -669,7 +676,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -762,7 +770,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -855,7 +864,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -933,7 +943,7 @@ } }, { - "description": "change stream resumes after NotMasterNoSlaveOk", + "description": "change stream resumes after NotPrimaryNoSecondaryOk", "minServerVersion": "4.3.1", "failPoint": { "configureFailPoint": "failGetMoreAfterCursorCheckout", @@ -948,7 +958,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1026,7 +1037,7 @@ } }, { - "description": "change stream resumes after NotMasterOrSecondary", + "description": "change stream resumes after NotPrimaryOrSecondary", "minServerVersion": "4.3.1", "failPoint": { "configureFailPoint": "failGetMoreAfterCursorCheckout", @@ -1041,7 +1052,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1134,7 +1146,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1227,7 +1240,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1320,7 +1334,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1413,7 +1428,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1512,7 +1528,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, @@ -1608,7 +1625,8 @@ "target": "collection", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ], "changeStreamPipeline": [], "changeStreamOptions": {}, diff --git a/tests/SpecTests/client-side-encryption/tests/aggregate.json b/tests/SpecTests/client-side-encryption/tests/aggregate.json index a9e79f9ed..7de725b71 100644 --- a/tests/SpecTests/client-side-encryption/tests/aggregate.json +++ b/tests/SpecTests/client-side-encryption/tests/aggregate.json @@ -150,18 +150,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -273,18 +261,6 @@ "command_name": "aggregate" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/awsTemporary.json b/tests/SpecTests/client-side-encryption/tests/awsTemporary.json new file mode 100644 index 000000000..10eb85fee --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/awsTemporary.json @@ -0,0 +1,225 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "Insert a document with auto encryption using the AWS provider with temporary credentials", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "awsTemporary": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + }, + { + "description": "Insert with invalid temporary credentials", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "awsTemporaryNoSessionToken": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + }, + "result": { + "errorContains": "security token" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/azureKMS.json b/tests/SpecTests/client-side-encryption/tests/azureKMS.json index bf651f428..f0f5329d7 100644 --- a/tests/SpecTests/client-side-encryption/tests/azureKMS.json +++ b/tests/SpecTests/client-side-encryption/tests/azureKMS.json @@ -109,7 +109,6 @@ "tests": [ { "description": "Insert a document with auto encryption using Azure KMS provider", - "skipReason": "PHPLIB-619 RHEL platform is missing Azure root certificate", "clientOptions": { "autoEncryptOpts": { "kmsProviders": { @@ -140,18 +139,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/basic.json b/tests/SpecTests/client-side-encryption/tests/basic.json index 3f9895fd5..3ed066f53 100644 --- a/tests/SpecTests/client-side-encryption/tests/basic.json +++ b/tests/SpecTests/client-side-encryption/tests/basic.json @@ -144,18 +144,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -283,18 +271,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/bulk.json b/tests/SpecTests/client-side-encryption/tests/bulk.json index ead90985a..1b62e5e8a 100644 --- a/tests/SpecTests/client-side-encryption/tests/bulk.json +++ b/tests/SpecTests/client-side-encryption/tests/bulk.json @@ -178,18 +178,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/count.json b/tests/SpecTests/client-side-encryption/tests/count.json index 24f46a110..9df8cd639 100644 --- a/tests/SpecTests/client-side-encryption/tests/count.json +++ b/tests/SpecTests/client-side-encryption/tests/count.json @@ -149,18 +149,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/countDocuments.json b/tests/SpecTests/client-side-encryption/tests/countDocuments.json index 3cf5fbca8..07ff97f26 100644 --- a/tests/SpecTests/client-side-encryption/tests/countDocuments.json +++ b/tests/SpecTests/client-side-encryption/tests/countDocuments.json @@ -150,18 +150,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/delete.json b/tests/SpecTests/client-side-encryption/tests/delete.json index 30fb453a9..a6f4ffde9 100644 --- a/tests/SpecTests/client-side-encryption/tests/delete.json +++ b/tests/SpecTests/client-side-encryption/tests/delete.json @@ -151,18 +151,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -276,18 +264,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/distinct.json b/tests/SpecTests/client-side-encryption/tests/distinct.json index 7a5f75c4a..9786b0781 100644 --- a/tests/SpecTests/client-side-encryption/tests/distinct.json +++ b/tests/SpecTests/client-side-encryption/tests/distinct.json @@ -161,18 +161,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/explain.json b/tests/SpecTests/client-side-encryption/tests/explain.json index 5ad46bc23..0e451e481 100644 --- a/tests/SpecTests/client-side-encryption/tests/explain.json +++ b/tests/SpecTests/client-side-encryption/tests/explain.json @@ -155,18 +155,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/find.json b/tests/SpecTests/client-side-encryption/tests/find.json index b7c5258a1..1feddab0e 100644 --- a/tests/SpecTests/client-side-encryption/tests/find.json +++ b/tests/SpecTests/client-side-encryption/tests/find.json @@ -160,18 +160,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -302,18 +290,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/findOneAndDelete.json b/tests/SpecTests/client-side-encryption/tests/findOneAndDelete.json index 6261d8601..e418a4581 100644 --- a/tests/SpecTests/client-side-encryption/tests/findOneAndDelete.json +++ b/tests/SpecTests/client-side-encryption/tests/findOneAndDelete.json @@ -148,18 +148,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/findOneAndReplace.json b/tests/SpecTests/client-side-encryption/tests/findOneAndReplace.json index d91bc0599..78baca843 100644 --- a/tests/SpecTests/client-side-encryption/tests/findOneAndReplace.json +++ b/tests/SpecTests/client-side-encryption/tests/findOneAndReplace.json @@ -147,18 +147,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/findOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/findOneAndUpdate.json index fad70609a..1d8585115 100644 --- a/tests/SpecTests/client-side-encryption/tests/findOneAndUpdate.json +++ b/tests/SpecTests/client-side-encryption/tests/findOneAndUpdate.json @@ -149,18 +149,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/gcpKMS.json b/tests/SpecTests/client-side-encryption/tests/gcpKMS.json index a715a7d15..297d5d0dc 100644 --- a/tests/SpecTests/client-side-encryption/tests/gcpKMS.json +++ b/tests/SpecTests/client-side-encryption/tests/gcpKMS.json @@ -141,18 +141,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/getMore.json b/tests/SpecTests/client-side-encryption/tests/getMore.json index cf2344222..ee99bf753 100644 --- a/tests/SpecTests/client-side-encryption/tests/getMore.json +++ b/tests/SpecTests/client-side-encryption/tests/getMore.json @@ -179,18 +179,6 @@ "command_name": "find" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/insert.json b/tests/SpecTests/client-side-encryption/tests/insert.json index 78fa8feba..cf2910fd7 100644 --- a/tests/SpecTests/client-side-encryption/tests/insert.json +++ b/tests/SpecTests/client-side-encryption/tests/insert.json @@ -131,18 +131,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -258,18 +246,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/keyAltName.json b/tests/SpecTests/client-side-encryption/tests/keyAltName.json index d062bed45..7f71b9dbe 100644 --- a/tests/SpecTests/client-side-encryption/tests/keyAltName.json +++ b/tests/SpecTests/client-side-encryption/tests/keyAltName.json @@ -131,18 +131,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/localKMS.json b/tests/SpecTests/client-side-encryption/tests/localKMS.json index e4d25309c..67c4ba130 100644 --- a/tests/SpecTests/client-side-encryption/tests/localKMS.json +++ b/tests/SpecTests/client-side-encryption/tests/localKMS.json @@ -114,18 +114,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/localSchema.json b/tests/SpecTests/client-side-encryption/tests/localSchema.json index 7071d6fef..4698520f6 100644 --- a/tests/SpecTests/client-side-encryption/tests/localSchema.json +++ b/tests/SpecTests/client-side-encryption/tests/localSchema.json @@ -136,18 +136,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/missingKey.json b/tests/SpecTests/client-side-encryption/tests/missingKey.json index ac8e8320b..275147bb7 100644 --- a/tests/SpecTests/client-side-encryption/tests/missingKey.json +++ b/tests/SpecTests/client-side-encryption/tests/missingKey.json @@ -140,18 +140,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "different" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/replaceOne.json b/tests/SpecTests/client-side-encryption/tests/replaceOne.json index 5cdb3d40f..975768681 100644 --- a/tests/SpecTests/client-side-encryption/tests/replaceOne.json +++ b/tests/SpecTests/client-side-encryption/tests/replaceOne.json @@ -148,18 +148,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/types.json b/tests/SpecTests/client-side-encryption/tests/types.json index 47e4c27a2..a070f8bff 100644 --- a/tests/SpecTests/client-side-encryption/tests/types.json +++ b/tests/SpecTests/client-side-encryption/tests/types.json @@ -103,18 +103,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -254,18 +242,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -405,18 +381,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -656,18 +620,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -807,18 +759,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -1057,18 +997,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -1214,18 +1142,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { @@ -1369,18 +1285,6 @@ } ], "expectations": [ - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/updateMany.json b/tests/SpecTests/client-side-encryption/tests/updateMany.json index fd1f4d12b..823909044 100644 --- a/tests/SpecTests/client-side-encryption/tests/updateMany.json +++ b/tests/SpecTests/client-side-encryption/tests/updateMany.json @@ -164,18 +164,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/SpecTests/client-side-encryption/tests/updateOne.json b/tests/SpecTests/client-side-encryption/tests/updateOne.json index bed763d72..23bada964 100644 --- a/tests/SpecTests/client-side-encryption/tests/updateOne.json +++ b/tests/SpecTests/client-side-encryption/tests/updateOne.json @@ -150,18 +150,6 @@ "command_name": "listCollections" } }, - { - "command_started_event": { - "command": { - "listCollections": 1, - "filter": { - "name": "datakeys" - }, - "$db": "keyvault" - }, - "command_name": "listCollections" - } - }, { "command_started_event": { "command": { diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index d942cf1e4..1cd47e968 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -23,6 +23,7 @@ use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertCount; use function PHPUnit\Framework\assertInstanceOf; +use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertNotEmpty; @@ -76,6 +77,26 @@ final class EventObserver implements CommandSubscriber 'commandFailedEvent' => CommandFailedEvent::class, ]; + /** + * These events are defined in the specification but unsupported by PHPLIB + * (e.g. CMAP events). + * + * @var array + */ + private static $unsupportedEvents = [ + 'poolCreatedEvent' => 1, + 'poolReadyEvent' => 1, + 'poolClearedEvent' => 1, + 'poolClosedEvent' => 1, + 'connectionCreatedEvent' => 1, + 'connectionReadyEvent' => 1, + 'connectionClosedEvent' => 1, + 'connectionCheckOutStartedEvent' => 1, + 'connectionCheckOutFailedEvent' => 1, + 'connectionCheckedOutEvent' => 1, + 'connectionCheckedInEvent' => 1, + ]; + /** @var array */ private $actualEvents = []; @@ -105,6 +126,15 @@ public function __construct(array $observeEvents, array $ignoreCommands, bool $o foreach ($observeEvents as $event) { assertIsString($event); + + /* Unlike Context::assertExpectedEventsForClients, which runs within + * a test, EventObserver is constructed via createEntities (before + * all tests). Ignoring events here allows tests within the file + * that don't assert these events to still execute. */ + if (isset(self::$unsupportedEvents[$event])) { + continue; + } + assertArrayHasKey($event, self::$supportedEvents); $this->observeEvents[self::$supportedEvents[$event]] = 1; } @@ -223,8 +253,7 @@ private function assertEvent($actual, stdClass $expected, string $message) private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass $expected, string $message): void { - // TODO: Assert hasServiceId (blocked on PHPC-1752) - Util::assertHasOnlyKeys($expected, ['command', 'commandName', 'databaseName']); + Util::assertHasOnlyKeys($expected, ['command', 'commandName', 'databaseName', 'hasServiceId']); if (isset($expected->command)) { assertIsObject($expected->command); @@ -241,12 +270,16 @@ private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass assertIsString($expected->databaseName); assertSame($actual->getDatabaseName(), $expected->databaseName, $message . ': databaseName matches'); } + + if (isset($expected->hasServiceId)) { + assertIsBool($expected->hasServiceId); + assertSame($actual->getServiceId() !== null, $expected->hasServiceId, $message . ': hasServiceId matches'); + } } private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdClass $expected, string $message): void { - // TODO: Assert hasServiceId (blocked on PHPC-1752) - Util::assertHasOnlyKeys($expected, ['reply', 'commandName']); + Util::assertHasOnlyKeys($expected, ['reply', 'commandName', 'hasServiceId']); if (isset($expected->reply)) { assertIsObject($expected->reply); @@ -258,17 +291,26 @@ private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdC assertIsString($expected->commandName); assertSame($actual->getCommandName(), $expected->commandName, $message . ': commandName matches'); } + + if (isset($expected->hasServiceId)) { + assertIsBool($expected->hasServiceId); + assertSame($actual->getServiceId() !== null, $expected->hasServiceId, $message . ': hasServiceId matches'); + } } private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $expected, string $message): void { - // TODO: Assert hasServiceId (blocked on PHPC-1752) - Util::assertHasOnlyKeys($expected, ['commandName']); + Util::assertHasOnlyKeys($expected, ['commandName', 'hasServiceId']); if (isset($expected->commandName)) { assertIsString($expected->commandName); assertSame($actual->getCommandName(), $expected->commandName, $message . ': commandName matches'); } + + if (isset($expected->hasServiceId)) { + assertIsBool($expected->hasServiceId); + assertSame($actual->getServiceId() !== null, $expected->hasServiceId, $message . ': hasServiceId matches'); + } } /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index e35ff631a..0ae0f36c9 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -21,6 +21,41 @@ class UnifiedSpecTest extends FunctionalTestCase { /** @var array */ private static $incompleteTests = [ + 'command-monitoring/pre-42-server-connection-id: command events do not include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', + 'command-monitoring/server-connection-id: command events include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', + // Many load balancer tests use CMAP events and/or assertNumberConnectionsCheckedOut + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: no connection is pinned if all documents are returned in the initial batch' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: pinned connections are returned when the cursor is drained' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: pinned connections are returned to the pool when the cursor is closed' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: pinned connections are not returned after an network error during getMore' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: pinned connections are returned after a network error during a killCursors request' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: pinned connections are not returned to the pool after a non-network error on getMore' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: aggregate pins the cursor to a connection' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: listCollections pins the cursor to a connection' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: listIndexes pins the cursor to a connection' => 'PHPC does not implement CMAP', + 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: change streams pin to a connection' => 'PHPC does not implement CMAP', + 'load-balancers/monitoring events include correct fields: poolClearedEvent events include serviceId' => 'PHPC does not implement CMAP', + 'load-balancers/load-balancers/state change errors are correctly handled: only connections for a specific serviceId are closed when pools are cleared' => 'PHPC does not implement CMAP', + 'load-balancers/state change errors are correctly handled: only connections for a specific serviceId are closed when pools are cleared' => 'PHPC does not implement CMAP', + 'load-balancers/state change errors are correctly handled: errors during the initial connection hello are ignored' => 'PHPC does not implement CMAP', + 'load-balancers/state change errors are correctly handled: stale errors are ignored' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: all operations go to the same mongos' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: transaction can be committed multiple times' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is not released after a non-transient CRUD error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is not released after a non-transient commit error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a non-transient abort error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a transient non-network CRUD error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a transient network CRUD error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a transient non-network commit error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a transient network commit error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a transient non-network abort error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released after a transient network abort error' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is released on successful abort' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is returned when a new transaction is started' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: pinned connection is returned when a non-transaction operation uses the session' => 'PHPC does not implement CMAP', + 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: a connection can be shared by a transaction and a cursor' => 'PHPC does not implement CMAP', + 'load-balancers/wait queue timeout errors include details about checked out connections: wait queue timeout errors include cursor statistics' => 'PHPC does not implement CMAP', + 'load-balancers/wait queue timeout errors include details about checked out connections: wait queue timeout errors include transaction statistics' => 'PHPC does not implement CMAP', // PHPC does not implement CMAP 'valid-pass/assertNumberConnectionsCheckedOut: basic assertion succeeds' => 'PHPC does not implement CMAP', 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', @@ -115,6 +150,19 @@ public function provideGridFSTests() return $this->provideTests(__DIR__ . '/gridfs/*.json'); } + /** + * @dataProvider provideLoadBalancers + */ + public function testLoadBalancers(UnifiedTestCase $test): void + { + self::$runner->run($test); + } + + public function provideLoadBalancers() + { + return $this->provideTests(__DIR__ . '/load-balancers/*.json'); + } + /** * @dataProvider provideSessionsTests */ diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index aee149d30..696268980 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -301,7 +301,6 @@ private function getServerVersion(): string */ private function getTopology(): string { - // TODO: detect load-balanced topologies once PHPLIB-671 is implemented switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_STANDALONE: return RunOnRequirement::TOPOLOGY_SINGLE; @@ -314,6 +313,9 @@ private function getTopology(): string ? RunOnRequirement::TOPOLOGY_SHARDED_REPLICASET : RunOnRequirement::TOPOLOGY_SHARDED; + case Server::TYPE_LOAD_BALANCER: + return RunOnRequirement::TOPOLOGY_LOAD_BALANCED; + default: throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); } diff --git a/tests/UnifiedSpecTests/command-monitoring/pre-42-server-connection-id.json b/tests/UnifiedSpecTests/command-monitoring/pre-42-server-connection-id.json new file mode 100644 index 000000000..141fbe584 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/pre-42-server-connection-id.json @@ -0,0 +1,101 @@ +{ + "description": "pre-42-server-connection-id", + "schemaVersion": "1.6", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "server-connection-id-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "coll" + } + } + ], + "initialData": [ + { + "databaseName": "server-connection-id-tests", + "collectionName": "coll", + "documents": [] + } + ], + "tests": [ + { + "description": "command events do not include server connection id", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "$or": true + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert", + "hasServerConnectionId": false + } + }, + { + "commandSucceededEvent": { + "commandName": "insert", + "hasServerConnectionId": false + } + }, + { + "commandStartedEvent": { + "commandName": "find", + "hasServerConnectionId": false + } + }, + { + "commandFailedEvent": { + "commandName": "find", + "hasServerConnectionId": false + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/server-connection-id.json b/tests/UnifiedSpecTests/command-monitoring/server-connection-id.json new file mode 100644 index 000000000..a8f27637f --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/server-connection-id.json @@ -0,0 +1,101 @@ +{ + "description": "server-connection-id", + "schemaVersion": "1.6", + "runOnRequirements": [ + { + "minServerVersion": "4.2" + } + ], + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "server-connection-id-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "coll" + } + } + ], + "initialData": [ + { + "databaseName": "server-connection-id-tests", + "collectionName": "coll", + "documents": [] + } + ], + "tests": [ + { + "description": "command events include server connection id", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "$or": true + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert", + "hasServerConnectionId": true + } + }, + { + "commandSucceededEvent": { + "commandName": "insert", + "hasServerConnectionId": true + } + }, + { + "commandStartedEvent": { + "commandName": "find", + "hasServerConnectionId": true + } + }, + { + "commandFailedEvent": { + "commandName": "find", + "hasServerConnectionId": true + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/cursors.json b/tests/UnifiedSpecTests/load-balancers/cursors.json new file mode 100644 index 000000000..6eddc0ebc --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/cursors.json @@ -0,0 +1,1238 @@ +{ + "description": "cursors are correctly pinned to connections for load-balanced clusters", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent", + "connectionReadyEvent", + "connectionClosedEvent", + "connectionCheckedOutEvent", + "connectionCheckedInEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + }, + { + "collection": { + "id": "collection1", + "database": "database0", + "collectionName": "coll1" + } + }, + { + "collection": { + "id": "collection2", + "database": "database0", + "collectionName": "coll2" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + }, + { + "collectionName": "coll1", + "databaseName": "database0Name", + "documents": [] + }, + { + "collectionName": "coll2", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "no connection is pinned if all documents are returned in the initial batch", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {} + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {} + }, + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": 0, + "firstBatch": { + "$$type": "array" + }, + "ns": { + "$$type": "string" + } + } + }, + "commandName": "find" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connections are returned when the cursor is drained", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 2 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 3 + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + }, + { + "name": "close", + "object": "cursor0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "firstBatch": { + "$$type": "array" + }, + "ns": { + "$$type": "string" + } + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": 0, + "ns": { + "$$type": "string" + }, + "nextBatch": { + "$$type": "array" + } + } + }, + "commandName": "getMore" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connections are returned to the pool when the cursor is closed", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "firstBatch": { + "$$type": "array" + }, + "ns": { + "$$type": "string" + } + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "killCursors" + } + }, + { + "commandSucceededEvent": { + "commandName": "killCursors" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connections are not returned after an network error during getMore", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "closeConnection": true + } + } + } + }, + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 2 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectError": { + "isClientError": true + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "firstBatch": { + "$$type": "array" + }, + "ns": { + "$$type": "string" + } + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + } + ] + } + ] + }, + { + "description": "pinned connections are returned after a network error during a killCursors request", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "killCursors" + ], + "closeConnection": true + } + } + } + }, + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "firstBatch": { + "$$type": "array" + }, + "ns": { + "$$type": "string" + } + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "killCursors" + } + }, + { + "commandFailedEvent": { + "commandName": "killCursors" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + } + ] + } + ] + }, + { + "description": "pinned connections are not returned to the pool after a non-network error on getMore", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 7 + } + } + } + }, + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 2 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectError": { + "errorCode": 7 + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": { + "$$type": "long" + }, + "firstBatch": { + "$$type": "array" + }, + "ns": { + "$$type": "string" + } + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + }, + { + "commandFailedEvent": { + "commandName": "getMore" + } + }, + { + "commandStartedEvent": { + "commandName": "killCursors" + } + }, + { + "commandSucceededEvent": { + "commandName": "killCursors" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "aggregate pins the cursor to a connection", + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [], + "batchSize": 2 + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "cursor": { + "batchSize": 2 + } + }, + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": 0, + "ns": { + "$$type": "string" + }, + "nextBatch": { + "$$type": "array" + } + } + }, + "commandName": "getMore" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "listCollections pins the cursor to a connection", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "name": "listCollections", + "object": "database0", + "arguments": { + "filter": {}, + "batchSize": 2 + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listCollections": 1, + "cursor": { + "batchSize": 2 + } + }, + "commandName": "listCollections", + "databaseName": "database0Name" + } + }, + { + "commandSucceededEvent": { + "commandName": "listCollections" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": { + "$$type": "string" + } + }, + "commandName": "getMore" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": 0, + "ns": { + "$$type": "string" + }, + "nextBatch": { + "$$type": "array" + } + } + }, + "commandName": "getMore" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "listIndexes pins the cursor to a connection", + "operations": [ + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + }, + "name": "x_1" + } + }, + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "y": 1 + }, + "name": "y_1" + } + }, + { + "name": "listIndexes", + "object": "collection0", + "arguments": { + "batchSize": 2 + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "createIndexes": "coll0", + "indexes": [ + { + "name": "x_1", + "key": { + "x": 1 + } + } + ] + }, + "commandName": "createIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "command": { + "createIndexes": "coll0", + "indexes": [ + { + "name": "y_1", + "key": { + "y": 1 + } + } + ] + }, + "commandName": "createIndexes" + } + }, + { + "commandSucceededEvent": { + "commandName": "createIndexes" + } + }, + { + "commandStartedEvent": { + "command": { + "listIndexes": "coll0", + "cursor": { + "batchSize": 2 + } + }, + "commandName": "listIndexes", + "databaseName": "database0Name" + } + }, + { + "commandSucceededEvent": { + "commandName": "listIndexes" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + }, + { + "commandSucceededEvent": { + "reply": { + "cursor": { + "id": 0, + "ns": { + "$$type": "string" + }, + "nextBatch": { + "$$type": "array" + } + } + }, + "commandName": "getMore" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "change streams pin to a connection", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "close", + "object": "changeStream0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "aggregate" + } + }, + { + "commandSucceededEvent": { + "commandName": "aggregate" + } + }, + { + "commandStartedEvent": { + "commandName": "killCursors" + } + }, + { + "commandSucceededEvent": { + "commandName": "killCursors" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/event-monitoring.json b/tests/UnifiedSpecTests/load-balancers/event-monitoring.json new file mode 100644 index 000000000..938c70bf3 --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/event-monitoring.json @@ -0,0 +1,184 @@ +{ + "description": "monitoring events include correct fields", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "uriOptions": { + "retryReads": false + }, + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent", + "poolClearedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "databaseName": "database0", + "collectionName": "coll0", + "documents": [] + } + ], + "tests": [ + { + "description": "command started and succeeded events include serviceId", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert", + "hasServiceId": true + } + }, + { + "commandSucceededEvent": { + "commandName": "insert", + "hasServiceId": true + } + } + ] + } + ] + }, + { + "description": "command failed events include serviceId", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "$or": true + } + }, + "expectError": { + "isError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find", + "hasServiceId": true + } + }, + { + "commandFailedEvent": { + "commandName": "find", + "hasServiceId": true + } + } + ] + } + ] + }, + { + "description": "poolClearedEvent events include serviceId", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "closeConnection": true + } + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {} + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find", + "hasServiceId": true + } + }, + { + "commandFailedEvent": { + "commandName": "find", + "hasServiceId": true + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "poolClearedEvent": { + "hasServiceId": true + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/lb-connection-establishment.json b/tests/UnifiedSpecTests/load-balancers/lb-connection-establishment.json new file mode 100644 index 000000000..0eaadf30c --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/lb-connection-establishment.json @@ -0,0 +1,58 @@ +{ + "description": "connection establishment for load-balanced clusters", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "uriOptions": { + "loadBalanced": false + }, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + } + ], + "tests": [ + { + "description": "operations against load balancers fail if URI contains loadBalanced=false", + "skipReason": "servers have not implemented LB support yet so they will not fail the connection handshake in this case", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1 + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/non-lb-connection-establishment.json b/tests/UnifiedSpecTests/load-balancers/non-lb-connection-establishment.json new file mode 100644 index 000000000..6aaa7bdf9 --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/non-lb-connection-establishment.json @@ -0,0 +1,92 @@ +{ + "description": "connection establishment if loadBalanced is specified for non-load balanced clusters", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "single", + "sharded" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "lbTrueClient", + "useMultipleMongoses": false, + "uriOptions": { + "loadBalanced": true + } + } + }, + { + "database": { + "id": "lbTrueDatabase", + "client": "lbTrueClient", + "databaseName": "lbTrueDb" + } + }, + { + "client": { + "id": "lbFalseClient", + "uriOptions": { + "loadBalanced": false + } + } + }, + { + "database": { + "id": "lbFalseDatabase", + "client": "lbFalseClient", + "databaseName": "lbFalseDb" + } + } + ], + "_yamlAnchors": { + "runCommandArguments": [ + { + "arguments": { + "commandName": "ping", + "command": { + "ping": 1 + } + } + } + ] + }, + "tests": [ + { + "description": "operations against non-load balanced clusters fail if URI contains loadBalanced=true", + "operations": [ + { + "name": "runCommand", + "object": "lbTrueDatabase", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1 + } + }, + "expectError": { + "errorContains": "Driver attempted to initialize in load balancing mode, but the server does not support this mode" + } + } + ] + }, + { + "description": "operations against non-load balanced clusters succeed if URI contains loadBalanced=false", + "operations": [ + { + "name": "runCommand", + "object": "lbFalseDatabase", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1 + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json b/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json new file mode 100644 index 000000000..4ab34b1fe --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json @@ -0,0 +1,514 @@ +{ + "description": "state change errors are correctly handled", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "_yamlAnchors": { + "observedEvents": [ + "connectionCreatedEvent", + "connectionReadyEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "connectionClosedEvent", + "poolClearedEvent" + ] + }, + "createEntities": [ + { + "client": { + "id": "failPointClient", + "useMultipleMongoses": false + } + }, + { + "client": { + "id": "singleClient", + "useMultipleMongoses": false, + "uriOptions": { + "appname": "lbSDAMErrorTestClient", + "retryWrites": false + }, + "observeEvents": [ + "connectionCreatedEvent", + "connectionReadyEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "connectionClosedEvent", + "poolClearedEvent" + ] + } + }, + { + "database": { + "id": "singleDB", + "client": "singleClient", + "databaseName": "singleDB" + } + }, + { + "collection": { + "id": "singleColl", + "database": "singleDB", + "collectionName": "singleColl" + } + }, + { + "client": { + "id": "multiClient", + "useMultipleMongoses": true, + "uriOptions": { + "retryWrites": false + }, + "observeEvents": [ + "connectionCreatedEvent", + "connectionReadyEvent", + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent", + "connectionCheckedInEvent", + "connectionClosedEvent", + "poolClearedEvent" + ] + } + }, + { + "database": { + "id": "multiDB", + "client": "multiClient", + "databaseName": "multiDB" + } + }, + { + "collection": { + "id": "multiColl", + "database": "multiDB", + "collectionName": "multiColl" + } + } + ], + "initialData": [ + { + "collectionName": "singleColl", + "databaseName": "singleDB", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + }, + { + "collectionName": "multiColl", + "databaseName": "multiDB", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + } + ], + "tests": [ + { + "description": "only connections for a specific serviceId are closed when pools are cleared", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "name": "createFindCursor", + "object": "multiColl", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "createFindCursor", + "object": "multiColl", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor1" + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "close", + "object": "cursor1" + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "multiClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 11600 + } + } + } + }, + { + "name": "insertOne", + "object": "multiColl", + "arguments": { + "document": { + "x": 1 + } + }, + "expectError": { + "errorCode": 11600 + } + }, + { + "name": "insertOne", + "object": "multiColl", + "arguments": { + "document": { + "x": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "multiClient", + "eventType": "cmap", + "events": [ + { + "connectionCreatedEvent": {} + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCreatedEvent": {} + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "stale" + } + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "errors during the initial connection hello are ignored", + "runOnRequirements": [ + { + "minServerVersion": "4.9" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "failPointClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "isMaster", + "hello" + ], + "closeConnection": true, + "appName": "lbSDAMErrorTestClient" + } + } + } + }, + { + "name": "insertOne", + "object": "singleColl", + "arguments": { + "document": { + "x": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "singleClient", + "eventType": "cmap", + "events": [ + { + "connectionCreatedEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + } + ] + } + ] + }, + { + "description": "errors during authentication are processed", + "runOnRequirements": [ + { + "auth": true + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "failPointClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "saslContinue" + ], + "closeConnection": true, + "appName": "lbSDAMErrorTestClient" + } + } + } + }, + { + "name": "insertOne", + "object": "singleColl", + "arguments": { + "document": { + "x": 1 + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "singleClient", + "eventType": "cmap", + "events": [ + { + "connectionCreatedEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionCheckOutFailedEvent": { + "reason": "connectionError" + } + } + ] + } + ] + }, + { + "description": "stale errors are ignored", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "failPointClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "getMore" + ], + "closeConnection": true + } + } + } + }, + { + "name": "createFindCursor", + "object": "singleColl", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "createFindCursor", + "object": "singleColl", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor1" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectError": { + "isClientError": true + } + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor1" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor1" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor1", + "expectError": { + "isClientError": true + } + }, + { + "name": "close", + "object": "cursor1" + } + ], + "expectEvents": [ + { + "client": "singleClient", + "eventType": "cmap", + "events": [ + { + "connectionCreatedEvent": {} + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCreatedEvent": {} + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "poolClearedEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": {} + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/server-selection.json b/tests/UnifiedSpecTests/load-balancers/server-selection.json new file mode 100644 index 000000000..00c7e4c95 --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/server-selection.json @@ -0,0 +1,82 @@ +{ + "description": "server selection for load-balanced clusters", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0", + "collectionOptions": { + "readPreference": { + "mode": "secondaryPreferred" + } + } + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "$readPreference is sent for load-balanced clusters", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "$readPreference": { + "mode": "secondaryPreferred" + } + }, + "commandName": "find", + "databaseName": "database0Name" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/transactions.json b/tests/UnifiedSpecTests/load-balancers/transactions.json new file mode 100644 index 000000000..8cf24f4ca --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/transactions.json @@ -0,0 +1,1621 @@ +{ + "description": "transactions are correctly pinned to connections for load-balanced clusters", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent", + "connectionReadyEvent", + "connectionClosedEvent", + "connectionCheckedOutEvent", + "connectionCheckedInEvent" + ] + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + } + ], + "_yamlAnchors": { + "documents": [ + { + "_id": 4 + } + ] + }, + "tests": [ + { + "description": "sessions are reused in LB mode", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "assertSameLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ] + }, + { + "description": "all operations go to the same mongos", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "commitTransaction", + "object": "session0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + } + ] + } + ] + }, + { + "description": "transaction can be committed multiple times", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is not released after a non-transient CRUD error", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 51 + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + }, + "expectError": { + "errorCode": 51, + "errorLabelsOmit": [ + "TransientTransactionError" + ] + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is not released after a non-transient commit error", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorCode": 51 + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0", + "expectError": { + "errorCode": 51, + "errorLabelsOmit": [ + "TransientTransactionError" + ] + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a non-transient abort error", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 51 + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a transient non-network CRUD error", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + }, + "expectError": { + "errorCode": 24, + "errorLabelsContain": [ + "TransientTransactionError" + ] + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a transient network CRUD error", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "closeConnection": true + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + }, + "expectError": { + "isClientError": true, + "errorLabelsContain": [ + "TransientTransactionError" + ] + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a transient non-network commit error", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0", + "expectError": { + "errorCode": 24, + "errorLabelsContain": [ + "TransientTransactionError" + ] + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a transient network commit error", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "commitTransaction" + ], + "closeConnection": true + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0", + "ignoreResultAndError": true + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a transient non-network abort error", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "errorCode": 24 + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released after a transient network abort error", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "abortTransaction" + ], + "closeConnection": true + } + } + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionClosedEvent": { + "reason": "error" + } + }, + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is released on successful abort", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is returned when a new transaction is started", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "commitTransaction", + "object": "session0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + } + ] + } + ] + }, + { + "description": "pinned connection is returned when a non-transaction operation uses the session", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "commitTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "commitTransaction" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + }, + { + "description": "a connection can be shared by a transaction and a cursor", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2, + "session": "session0" + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "close", + "object": "cursor0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 1 + } + }, + { + "name": "abortTransaction", + "object": "session0" + }, + { + "name": "assertNumberConnectionsCheckedOut", + "object": "testRunner", + "arguments": { + "client": "client0", + "connections": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "commandName": "killCursors" + } + }, + { + "commandStartedEvent": { + "commandName": "abortTransaction" + } + } + ] + }, + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionReadyEvent": {} + }, + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckedInEvent": {} + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/load-balancers/wait-queue-timeouts.json b/tests/UnifiedSpecTests/load-balancers/wait-queue-timeouts.json new file mode 100644 index 000000000..3dc6e46cf --- /dev/null +++ b/tests/UnifiedSpecTests/load-balancers/wait-queue-timeouts.json @@ -0,0 +1,153 @@ +{ + "description": "wait queue timeout errors include details about checked out connections", + "schemaVersion": "1.3", + "runOnRequirements": [ + { + "topologies": [ + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "uriOptions": { + "maxPoolSize": 1, + "waitQueueTimeoutMS": 50 + }, + "observeEvents": [ + "connectionCheckedOutEvent", + "connectionCheckOutFailedEvent" + ] + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + } + ], + "tests": [ + { + "description": "wait queue timeout errors include cursor statistics", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + } + }, + "expectError": { + "isClientError": true, + "errorContains": "maxPoolSize: 1, connections in use by cursors: 1, connections in use by transactions: 0, connections in use by other operations: 0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckOutFailedEvent": {} + } + ] + } + ] + }, + { + "description": "wait queue timeout errors include transaction statistics", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + }, + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "x": 1 + } + }, + "expectError": { + "isClientError": true, + "errorContains": "maxPoolSize: 1, connections in use by cursors: 0, connections in use by transactions: 1, connections in use by other operations: 0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionCheckedOutEvent": {} + }, + { + "connectionCheckOutFailedEvent": {} + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/poc-crud.json b/tests/UnifiedSpecTests/valid-pass/poc-crud.json index 7bb072de8..0790d9b78 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-crud.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-crud.json @@ -323,7 +323,8 @@ "topologies": [ "replicaset", "sharded-replicaset" - ] + ], + "serverless": "forbid" } ], "operations": [ From 3a0bef409071513fe6764cfa8dec60a5bf24ad45 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 19 Oct 2021 15:54:57 -0400 Subject: [PATCH 087/321] PHPLIB-743: Ignore extra metadata queries in CSFLE spec tests --- tests/SpecTests/CommandExpectations.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index ae4ac2eee..8575eb8fe 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -39,6 +39,9 @@ class CommandExpectations implements CommandSubscriber /** @var boolean */ private $ignoreExtraEvents = false; + /** @var boolean */ + private $ignoreKeyVaultListCollections = false; + /** @var string[] */ private $ignoredCommandNames = []; @@ -87,6 +90,7 @@ public static function fromClientSideEncryption(array $expectedEvents) $o->ignoreCommandFailed = true; $o->ignoreCommandSucceeded = true; + $o->ignoreKeyVaultListCollections = true; return $o; } @@ -254,7 +258,24 @@ public function assert(FunctionalTestCase $test, Context $context): void private function isEventIgnored($event) { - return ($this->ignoreExtraEvents && count($this->actualEvents) === count($this->expectedEvents)) - || in_array($event->getCommandName(), $this->ignoredCommandNames); + if ($this->ignoreExtraEvents && count($this->actualEvents) === count($this->expectedEvents)) { + return true; + } + + if (in_array($event->getCommandName(), $this->ignoredCommandNames)) { + return true; + } + + /* Note: libmongoc does not use a separate MongoClient to query for + * CSFLE metadata (DRIVERS-1459). Since the tests do not expect this + * command, we must ignore it. */ + if ( + $this->ignoreKeyVaultListCollections && $event instanceof CommandStartedEvent && + $event->getCommandName() === 'listCollections' && $event->getDatabaseName() === 'keyvault' + ) { + return true; + } + + return false; } } From 88d74b8f04a9b12e122c9e380e2149db48a84959 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 20 Oct 2021 10:06:28 -0400 Subject: [PATCH 088/321] PHPLIB-518: Don't assert error codes for pre-3.2 servers in renameCollection tests --- .../Operation/RenameCollectionFunctionalTest.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/Operation/RenameCollectionFunctionalTest.php b/tests/Operation/RenameCollectionFunctionalTest.php index 6df2f16ff..d1fa52e0a 100644 --- a/tests/Operation/RenameCollectionFunctionalTest.php +++ b/tests/Operation/RenameCollectionFunctionalTest.php @@ -107,8 +107,11 @@ public function testRenameCollectionExistingTarget(): void $this->expectException(CommandException::class); - // mongos returns an inconsistent error code (see: SERVER-60632) - if (! $this->isShardedCluster()) { + /* TODO: mongos returns an inconsistent error code (see: SERVER-60632) + * + * Note: pre-3.2 server versions omit an error code. libmongoc will + * substitute MONGOC_ERROR_QUERY_FAILURE in _mongoc_cmd_check_ok. */ + if (! $this->isShardedCluster() && version_compare($this->getServerVersion(), '3.2.0', '>=')) { $this->expectExceptionCode(self::$errorCodeNamespaceExists); } @@ -124,7 +127,13 @@ public function testRenameCollectionExistingTarget(): void public function testRenameNonexistentCollection(): void { $this->expectException(CommandException::class); - $this->expectExceptionCode(self::$errorCodeNamespaceNotFound); + + /* Note: pre-3.2 server versions omit an error code. libmongoc will + * substitute MONGOC_ERROR_QUERY_FAILURE in _mongoc_cmd_check_ok */ + if (version_compare($this->getServerVersion(), '3.2.0', '>=')) { + $this->expectExceptionCode(self::$errorCodeNamespaceNotFound); + } + $operation = new RenameCollection( $this->getDatabaseName(), $this->getCollectionName(), From b0bbd657f84219212487d01a8ffe93a789e1e488 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 20 Oct 2021 13:56:24 -0400 Subject: [PATCH 089/321] PHPLIB-739, PHPLIB-745: Update aggregate-write-readPreference tests Skips $out tests for serverless environments and bumps minServerVersion to 4.2 for tests expecting a readConcern to be passed alongside a write stage. Synced with mongodb/specifications@dce2c48e697e9a7d08faad871e86b415bb481df7 --- .../crud/aggregate-write-readPreference.json | 9 ++++++--- .../crud/db-aggregate-write-readPreference.json | 7 +++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json b/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json index 2bb1945ba..bc887e83c 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json +++ b/tests/UnifiedSpecTests/crud/aggregate-write-readPreference.json @@ -1,6 +1,6 @@ { "description": "aggregate-write-readPreference", - "schemaVersion": "1.3", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "3.6", @@ -90,7 +90,8 @@ "description": "Aggregate with $out includes read preference for 5.0+ server", "runOnRequirements": [ { - "minServerVersion": "5.0" + "minServerVersion": "5.0", + "serverless": "forbid" } ], "operations": [ @@ -180,7 +181,9 @@ "description": "Aggregate with $out omits read preference for pre-5.0 server", "runOnRequirements": [ { - "maxServerVersion": "4.4.99" + "minServerVersion": "4.2", + "maxServerVersion": "4.4.99", + "serverless": "forbid" } ], "operations": [ diff --git a/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json b/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json index a89e79500..2a81282de 100644 --- a/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json +++ b/tests/UnifiedSpecTests/crud/db-aggregate-write-readPreference.json @@ -64,7 +64,8 @@ "description": "Database-level aggregate with $out includes read preference for 5.0+ server", "runOnRequirements": [ { - "minServerVersion": "5.0" + "minServerVersion": "5.0", + "serverless": "forbid" } ], "operations": [ @@ -157,7 +158,9 @@ "description": "Database-level aggregate with $out omits read preference for pre-5.0 server", "runOnRequirements": [ { - "maxServerVersion": "4.4.99" + "minServerVersion": "4.2", + "maxServerVersion": "4.4.99", + "serverless": "forbid" } ], "operations": [ From feccdaafbcd059b53cc08bf755f70d1e79281007 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 29 Oct 2021 17:00:40 -0400 Subject: [PATCH 090/321] Master is now 1.11-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4493881cc..bb17e2c5e 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.10.x-dev" + "dev-master": "1.11.x-dev" } } } From 37996bb8f9fec96add92a219adf67b3cfd62b1ad Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 2 Nov 2021 11:40:32 -0400 Subject: [PATCH 091/321] PHPLIB-758: Use https:// instead of git:// for git clone --- .evergreen/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 69c15d429..ddd6d5d41 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -92,7 +92,7 @@ functions: # If this was a patch build, doing a fresh clone would not actually test the patch cp -R ${PROJECT_DIRECTORY}/ $DRIVERS_TOOLS else - git clone git://github.com/mongodb-labs/drivers-evergreen-tools.git $DRIVERS_TOOLS + git clone https://github.com/mongodb-labs/drivers-evergreen-tools.git $DRIVERS_TOOLS fi echo "{ \"releases\": { \"default\": \"$MONGODB_BINARIES\" }}" > $MONGO_ORCHESTRATION_HOME/orchestration.config From d9b563b41f21a7152f127f4d997daa46bcbc0bbe Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 2 Nov 2021 17:18:50 -0400 Subject: [PATCH 092/321] Update release notes template and forum link --- CONTRIBUTING.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee2d45332..90c56b0ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -203,9 +203,9 @@ https://docs.mongodb.com/php-library/ This library may be installed or upgraded with: - composer require mongodb/mongodb + composer require mongodb/mongodb^X.Y.Z -Installation instructions for the `mongodb` extension may be found in the [PHP.net documentation](http://php.net/manual/en/mongodb.installation.php). +Installation instructions for the `mongodb` extension may be found in the [PHP.net documentation](https://www.php.net/manual/en/mongodb.installation.php). ``` The URL for the list of resolved JIRA issues will need to be updated with each @@ -223,10 +223,7 @@ Thanks for our community contributors for this release: * [$CONTRIBUTOR_NAME](https://github.com/$GITHUB_USERNAME) ``` -Release announcements should also be sent to the [MongoDB Product & Driver Announcements](https://community.mongodb.com/tags/c/community/release-notes/35/php-driver). - -Consider announcing each release on Twitter. Significant releases should also be -announced via [@MongoDB](http://twitter.com/mongodb) as well. +Release announcements should also be posted in the [MongoDB Product & Driver Announcements: Driver Releases](https://www.mongodb.com/community/forums/tags/c/announcements/driver-releases/110/php) forum and shared on Twitter. ### Documentation Updates for New Major and Minor Versions From f7b9ba2229737e3ad830c62833029426a130f3db Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 10 Nov 2021 10:22:36 -0500 Subject: [PATCH 093/321] PHPLIB-672: Drop support for PHP 7.1 (#868) * PHPLIB-672: Drop support for PHP 7.1 This commit also removes the old bootstrap file for PHPUnit, since it's no longer relevant. The class aliases were previously introduced in a8b48629cd52ed96f04a818e9c3b15a2bd79864d and 016eb3e46dfabd450c75cadc9da354285c8aa3d9 and should no longer be necessary for PHPUnit 8+. * PHPLIB-672: Update Evergreen config for PHP 7.2+, driver 1.11, and MongoDB 5.0 Bump edge-versions:latest-stable to MongoDB 5.0. Drops PHP 7.1 and adds PHP 8.0 to php-versions and php-edge-versions. Revert various tests to latest-stable driver version now that 1.11 exists. Use debian92 for feature-based testing (e.g. Atlas Data Lake). Make display names consistent, which will make it easier to find redundant build variants. * Serverless scripts expect to be run with bash --- .evergreen/config.yml | 119 ++++++++++++++------------ composer.json | 2 +- phpunit.evergreen.xml | 2 +- phpunit.xml.dist | 2 +- tests/GridFS/BucketFunctionalTest.php | 7 +- tests/bootstrap.php | 23 ----- 6 files changed, 68 insertions(+), 87 deletions(-) delete mode 100644 tests/bootstrap.php diff --git a/.evergreen/config.yml b/.evergreen/config.yml index ddd6d5d41..c1de0046a 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -212,7 +212,7 @@ functions: export SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} export SERVERLESS_ATLAS_USER=${SERVERLESS_ATLAS_USER} export SERVERLESS_ATLAS_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} - sh ${PROJECT_DIRECTORY}/.evergreen/serverless/create-instance.sh + bash ${PROJECT_DIRECTORY}/.evergreen/serverless/create-instance.sh - command: expansions.update params: file: src/serverless-expansion.yml @@ -229,7 +229,7 @@ functions: export SERVERLESS_ATLAS_USER=${SERVERLESS_ATLAS_USER} export SERVERLESS_ATLAS_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} export SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} - sh ${PROJECT_DIRECTORY}/.evergreen/serverless/delete-instance.sh + bash ${PROJECT_DIRECTORY}/.evergreen/serverless/delete-instance.sh "run tests": - command: shell.exec @@ -472,37 +472,39 @@ tasks: axes: + # Note: install-dependencies.sh will search for the latest minor version + # matching the PHP_VERSION constant - id: php-versions display_name: PHP Version values: + - id: "8.0" + display_name: "8.0" + variables: + PHP_VERSION: "8.0" - id: "7.4" display_name: "7.4" variables: - PHP_VERSION: "7.4.7" + PHP_VERSION: "7.4" - id: "7.3" display_name: "7.3" variables: - PHP_VERSION: "7.3.8" + PHP_VERSION: "7.3" - id: "7.2" display_name: "7.2" variables: - PHP_VERSION: "7.2.21" - - id: "7.1" - display_name: "7.1" - variables: - PHP_VERSION: "7.1.31" + PHP_VERSION: "7.2" - id: php-edge-versions display_name: PHP Version values: - id: "latest-stable" - display_name: "7.4" + display_name: "8.0" variables: - PHP_VERSION: "7.4.7" + PHP_VERSION: "8.0" - id: "oldest-supported" - display_name: "7.1" + display_name: "7.2" variables: - PHP_VERSION: "7.1.31" + PHP_VERSION: "7.2" - id: versions display_name: MongoDB Version @@ -548,9 +550,9 @@ axes: display_name: MongoDB Version values: - id: "latest-stable" - display_name: "4.4" + display_name: "5.0" variables: - VERSION: "4.4" + VERSION: "5.0" - id: "oldest-supported" display_name: "3.0" variables: @@ -559,25 +561,24 @@ axes: - id: driver-versions display_name: Driver Version values: - # * lowest-supported can be enabled once a 1.10 patch release has been tagged -# - id: "lowest-supported" -# display_name: "1.10.0" -# variables: -# EXTENSION_VERSION: "1.10.0" -# - id: "latest-stable" -# display_name: "Latest Stable (1.10.x)" -# variables: -# EXTENSION_VERSION: "stable" -# - id: "upcoming-stable" -# display_name: "1.10-dev" -# variables: -# EXTENSION_BRANCH: "v1.10" + - id: "lowest-supported" + display_name: "1.11.0" + variables: + EXTENSION_VERSION: "1.11.0" + - id: "latest-stable" + display_name: "Latest Stable (1.11.x)" + variables: + EXTENSION_VERSION: "stable" + - id: "upcoming-stable" + display_name: "1.11-dev" + variables: + EXTENSION_BRANCH: "v1.11" - id: "latest-dev" - display_name: "1.11-dev (master)" + display_name: "1.12-dev (master)" variables: EXTENSION_BRANCH: "master" - - id: os-php7 + - id: os display_name: OS values: - id: debian92-test @@ -662,76 +663,80 @@ axes: buildvariants: -# Tests all PHP versions on all operating systems. -# Only tests against latest MongoDB and ext-mongodb versions +# Tests all PHP versions on all operating systems and latest MongoDB and ext-mongodb versions - matrix_name: "test-php-versions" - matrix_spec: {"os-php7": "*", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "latest-dev" } + matrix_spec: { "os": "*", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-stable" } exclude_spec: # rhel71-power8 fails due to not reaching pecl - - { "os-php7": "rhel71-power8", "php-versions": "*", edge-versions: "*", "driver-versions": "*" } + - { "os": "rhel71-power8", "edge-versions": "*", "php-versions": "*", "driver-versions": "*" } # rhel74-zseries doesn't start in a timely fashion - most likely missing executors - - { "os-php7": "rhel74-zseries", "php-versions": "*", edge-versions: "*", "driver-versions": "*" } - display_name: "* ${os-php7}, PHP ${php-versions}, MongoDB ${edge-versions}, ext-mongodb ${driver-versions}" + - { "os": "rhel74-zseries", "edge-versions": "*", "php-versions": "*", "driver-versions": "*" } + # rhel70 does not have PHP 8.0 + - { "os": "rhel70-test", "edge-versions": "*", "php-versions": "8.0", "driver-versions": "*" } + display_name: "${os}, MongoDB ${edge-versions}, PHP ${php-versions}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests all driver versions on all PHP versions -# Only tests on Ubuntu 18.04 and latest MongoDB +# Tests all driver versions on all PHP versions using latest MongoDB and Ubuntu 18.04 - matrix_name: "test-driver-versions" - matrix_spec: {"os-php7": "ubuntu1804-arm64-test", "php-versions": "*", "edge-versions": "latest-stable", "driver-versions": "*" } - display_name: "ext-mongodb ${driver-versions}, PHP ${php-versions}, ${os-php7}, MongoDB ${edge-versions}" + matrix_spec: { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "*" } + exclude_spec: + # Avoid duplicate build variants from test-php-versions + - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-stable" } + display_name: "${os}, MongoDB ${edge-versions}, PHP ${php-versions}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests all MongoDB versions -# Only tests on Ubuntu 18.04, with latest stable PHP and driver versions -# Tests against various topologies +# Tests all MongoDB versions with latest stable PHP and driver versions - matrix_name: "test-mongodb-versions" - matrix_spec: {"os-php7": "rhel70-test", "php-edge-versions": "latest-stable", "versions": "*", "driver-versions": "latest-dev" } - display_name: "MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" + matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + exclude_spec: + # Avoid duplicate build variants from test-php-versions (assumes edge-versions:latest-stable is 5.0) + - { "os": "debian92-test", "versions": "5.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "${os}, MongoDB ${versions}, PHP ${php-edge-versions}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests oldest supported version +# Tests all MongoDB versions with lowest supported PHP and driver versions # Enables --prefer-lowest for composer to test oldest dependencies against all server versions -# TODO: driver-versions can be changed back to lowest-supported when that version is enabled in the axis - matrix_name: "test-dependencies" - matrix_spec: { "dependencies": "lowest", "os-php7": "rhel70-test", "php-edge-versions": "oldest-supported", "versions": "*", "driver-versions": "latest-dev" } - display_name: "Dependencies: ${dependencies}, MongoDB ${versions}, PHP ${php-edge-versions}, ${os-php7}, ext-mongodb ${driver-versions}" + matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "oldest-supported", "driver-versions": "lowest-supported", "dependencies": "lowest" } + display_name: "Lowest Dependencies: ${os}, MongoDB ${versions}, PHP ${php-edge-versions}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" - name: "test-replica_set" - name: "test-sharded_cluster" - matrix_name: "atlas-data-lake-test" - matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-dev" } - display_name: "Atlas Data Lake test" - run_on: rhel70 + matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "Atlas Data Lake" + run_on: debian92-test tasks: - name: "test-atlas-data-lake" - matrix_name: "test-versioned-api" - matrix_spec: { "php-edge-versions": "latest-stable", "versions": ["5.0", "latest"], "driver-versions": "latest-dev" } + matrix_spec: { "versions": ["5.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Versioned API - ${versions}" - run_on: rhel70 + run_on: debian92-test tasks: - .versioned-api - matrix_name: "serverless" - matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-dev" } + matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Serverless" - run_on: rhel70 + run_on: debian92-test tasks: - .serverless - matrix_name: "test-loadBalanced" - matrix_spec: { "os-php7": "debian92-test", "php-versions": "7.3", "versions": ["5.0", "latest"], "driver-versions": "latest-dev" } + matrix_spec: { "versions": ["5.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Load balanced - ${versions}" + run_on: debian92-test tasks: - name: "test-loadBalanced" diff --git a/composer.json b/composer.json index bb17e2c5e..a0b0ca6e3 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ { "name": "Jeremy Mikola", "email": "jmikola@gmail.com" } ], "require": { - "php": "^7.1 || ^8.0", + "php": "^7.2 || ^8.0", "ext-hash": "*", "ext-json": "*", "ext-mongodb": "^1.11.0", diff --git a/phpunit.evergreen.xml b/phpunit.evergreen.xml index fae1bdf0e..f9832761a 100644 --- a/phpunit.evergreen.xml +++ b/phpunit.evergreen.xml @@ -6,7 +6,7 @@ beStrictAboutOutputDuringTests="true" beStrictAboutChangesToGlobalState="true" colors="true" - bootstrap="tests/bootstrap.php" + bootstrap="vendor/autoload.php" defaultTestSuite="Default Test Suite" > diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 13d1fdd41..d5ec557d1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,7 +6,7 @@ beStrictAboutOutputDuringTests="true" beStrictAboutChangesToGlobalState="true" colors="true" - bootstrap="tests/bootstrap.php" + bootstrap="vendor/autoload.php" defaultTestSuite="Default Test Suite" > diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 79c5f345f..afeba2ae2 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -14,7 +14,6 @@ use MongoDB\Model\BSONDocument; use MongoDB\Model\IndexInfo; use MongoDB\Operation\ListIndexes; -use PHPUnit\Framework\Error\Warning; use function array_merge; use function call_user_func; @@ -174,7 +173,7 @@ public function testDownloadingFileWithMissingChunk(): void $this->chunksCollection->deleteOne(['files_id' => $id, 'n' => 0]); - $this->expectException(Warning::class); + $this->expectWarning(); stream_get_contents($this->bucket->openDownloadStream($id)); } @@ -187,7 +186,7 @@ public function testDownloadingFileWithUnexpectedChunkIndex(): void ['$set' => ['n' => 1]] ); - $this->expectException(Warning::class); + $this->expectWarning(); stream_get_contents($this->bucket->openDownloadStream($id)); } @@ -200,7 +199,7 @@ public function testDownloadingFileWithUnexpectedChunkSize(): void ['$set' => ['data' => new Binary('fooba', Binary::TYPE_GENERIC)]] ); - $this->expectException(Warning::class); + $this->expectWarning(); stream_get_contents($this->bucket->openDownloadStream($id)); } diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index 31649c704..000000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,23 +0,0 @@ - Date: Fri, 12 Nov 2021 17:57:20 -0500 Subject: [PATCH 094/321] PHPLIB-592: Allow GridFS StreamWrapper to throw exceptions (#869) Previously, exceptions were converted to E_USER_WARNING with a false return value for consistency with PHP's stream API (e.g. fread). This is not actually required and allowing the original exception to be propagated is likely more helpful for users and simplifies some handling in the spec test runner. --- src/GridFS/StreamWrapper.php | 21 ++------------------- tests/GridFS/BucketFunctionalTest.php | 10 +++++++--- tests/UnifiedSpecTests/Operation.php | 12 ++++-------- 3 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index 38614853b..67baaf287 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -19,20 +19,15 @@ use MongoDB\BSON\UTCDateTime; use stdClass; -use Throwable; use function explode; -use function get_class; use function in_array; use function is_integer; -use function sprintf; use function stream_context_get_options; use function stream_get_wrappers; use function stream_wrapper_register; use function stream_wrapper_unregister; -use function trigger_error; -use const E_USER_WARNING; use const SEEK_CUR; use const SEEK_END; use const SEEK_SET; @@ -162,13 +157,7 @@ public function stream_read($length) return ''; } - try { - return $this->stream->readBytes($length); - } catch (Throwable $e) { - trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), E_USER_WARNING); - - return false; - } + return $this->stream->readBytes($length); } /** @@ -259,13 +248,7 @@ public function stream_write($data) return 0; } - try { - return $this->stream->writeBytes($data); - } catch (Throwable $e) { - trigger_error(sprintf('%s: %s', get_class($e), $e->getMessage()), E_USER_WARNING); - - return false; - } + return $this->stream->writeBytes($data); } /** diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index afeba2ae2..f00e23049 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -9,6 +9,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\Bucket; +use MongoDB\GridFS\Exception\CorruptFileException; use MongoDB\GridFS\Exception\FileNotFoundException; use MongoDB\GridFS\Exception\StreamException; use MongoDB\Model\BSONDocument; @@ -173,7 +174,8 @@ public function testDownloadingFileWithMissingChunk(): void $this->chunksCollection->deleteOne(['files_id' => $id, 'n' => 0]); - $this->expectWarning(); + $this->expectException(CorruptFileException::class); + $this->expectExceptionMessage('Chunk not found for index "0"'); stream_get_contents($this->bucket->openDownloadStream($id)); } @@ -186,7 +188,8 @@ public function testDownloadingFileWithUnexpectedChunkIndex(): void ['$set' => ['n' => 1]] ); - $this->expectWarning(); + $this->expectException(CorruptFileException::class); + $this->expectExceptionMessage('Expected chunk to have index "0" but found "1"'); stream_get_contents($this->bucket->openDownloadStream($id)); } @@ -199,7 +202,8 @@ public function testDownloadingFileWithUnexpectedChunkSize(): void ['$set' => ['data' => new Binary('fooba', Binary::TYPE_GENERIC)]] ); - $this->expectWarning(); + $this->expectException(CorruptFileException::class); + $this->expectExceptionMessage('Expected chunk to have size "6" but found "5"'); stream_get_contents($this->bucket->openDownloadStream($id)); } diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index e22a8bdf3..d5991f6ce 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -17,8 +17,8 @@ use MongoDB\Operation\FindOneAndReplace; use MongoDB\Operation\FindOneAndUpdate; use PHPUnit\Framework\Assert; -use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\Constraint\IsType; +use PHPUnit\Framework\Exception as PHPUnitException; use stdClass; use Throwable; @@ -146,18 +146,14 @@ public function assert(bool $rethrowExceptions = false): void $result = $this->execute(); $saveResultAsEntity = $this->saveResultAsEntity; } catch (Throwable $e) { - /* Rethrow any internal PHP errors and PHPUnit assertion failures, - * since those are never expected for "expectError". - * - * Note: we must be selective about what PHPUnit exceptions to pass - * through, as PHPUnit's Warning exception must be considered for - * expectError in GridFS tests (see: PHPLIB-592). + /* Rethrow any internal PHP errors and PHPUnit exceptions, since + * those are never expected for "expectError". * * TODO: Consider adding operation details (e.g. operations[] index) * to the exception message. Alternatively, throw a new exception * and include this as the previous, since PHPUnit will render the * chain when reporting a test failure. */ - if ($e instanceof Error || $e instanceof AssertionFailedError) { + if ($e instanceof Error || $e instanceof PHPUnitException) { throw $e; } From 42b9f2e4a9263b782503aabed07866f9ea0ac387 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 29 Nov 2021 17:39:04 -0500 Subject: [PATCH 095/321] PHPLIB-765: Remove links to legacy extension docs (#872) --- README.md | 8 +- docs/index.txt | 7 +- docs/reference/bson.txt | 6 +- .../method/MongoDBClient__construct.txt | 2 +- docs/upgrade.txt | 157 +++++++++--------- 5 files changed, 86 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index cc8bdd9af..ad9811a66 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ This library provides a high-level abstraction around the lower-level [PHP driver](https://github.com/mongodb/mongo-php-driver) (`mongodb` extension). While the extension provides a limited API for executing commands, queries, and -write operations, this library implements an API similar to that of the -[legacy PHP driver](https://php.net/manual/en/book.mongo.php). It contains -abstractions for client, database, and collection objects, and provides methods -for CRUD operations and common commands (e.g. index and collection management). +write operations, this library implements a full-featured API similar to that of +other MongoDB drivers. It contains abstractions for client, database, and +collection objects, and provides methods for CRUD operations and common commands +(e.g. index and collection management). If you are developing an application with MongoDB, you should consider using this library, or another high-level abstraction, instead of the extension alone. diff --git a/docs/index.txt b/docs/index.txt index ffdd4b16f..8c167eb63 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -35,10 +35,9 @@ following pages should help you get started: - :doc:`/reference/bson` -If you have previously worked with the -`legacy PHP driver `_ (i.e. ``mongo`` -extension), it will be helpful to review the :doc:`/upgrade` for a summary of -API changes between the old driver and this library. +If you have previously worked with the legacy ``mongo`` extension, it will be +helpful to review the :doc:`/upgrade` for a summary of API changes between the +old driver and this library. New to MongoDB? --------------- diff --git a/docs/reference/bson.txt b/docs/reference/bson.txt index c366ea8a8..b465ef619 100644 --- a/docs/reference/bson.txt +++ b/docs/reference/bson.txt @@ -199,9 +199,9 @@ The same document in the MongoDB shell might display as: Emulating the Legacy Driver --------------------------- -The legacy :php:`mongo extension ` returned both BSON documents and -arrays as PHP arrays. While PHP arrays are convenient to work with, this -behavior was problematic: +The legacy ``mongo`` extension returned both BSON documents and arrays as PHP +arrays. While PHP arrays are convenient to work with, this behavior was +problematic: - Different BSON types could deserialize to the same PHP value (e.g. ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the diff --git a/docs/reference/method/MongoDBClient__construct.txt b/docs/reference/method/MongoDBClient__construct.txt index ad864d186..091ae6144 100644 --- a/docs/reference/method/MongoDBClient__construct.txt +++ b/docs/reference/method/MongoDBClient__construct.txt @@ -113,7 +113,7 @@ By default, the |php-library| deserializes BSON documents and arrays as :phpclass:`MongoDB\\Model\\BSONDocument` and :phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. The following example demonstrates how to have the library unserialize everything as a PHP -array, as was done in the legacy :php:`mongo extension `. +array, as was done in the legacy ``mongo`` extension. .. code-block:: php diff --git a/docs/upgrade.txt b/docs/upgrade.txt index d783f13ae..b785b6557 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -14,22 +14,20 @@ Overview -------- The |php-library| and underlying :php:`mongodb extension ` have notable -API differences from the legacy :php:`mongo extension `. This page will -summarize those differences for the benefit of those upgrading from the legacy -driver. +API differences from the legacy ``mongo`` extension. This page will summarize +those differences for the benefit of those upgrading from the legacy driver. Additionally, a community-developed `mongo-php-adapter `_ library exists, which -implements the `mongo extension `_ API using this library -and the new driver. While this adapter library is not officially supported by -MongoDB, it does bear mentioning. +implements the ``mongo`` extension API using this library and the new driver. +While this adapter library is not officially supported by MongoDB, it does bear +mentioning. BSON Type Classes ----------------- -When upgrading from the legacy driver, -`type classes `_ such as -:php:`MongoId ` must be replaced with classes in the +When upgrading from the legacy driver, type classes such as MongoId must be +replaced with classes in the `MongoDB\\BSON namespace `_. The new driver also introduces interfaces for its BSON types, which should be preferred if applications need to type hint against BSON values. @@ -44,54 +42,54 @@ the new driver. - BSON type class - BSON type interface - * - :php:`MongoId ` + * - MongoId - :php:`MongoDB\\BSON\\ObjectId ` - :php:`MongoDB\\BSON\\ObjectIdInterface ` - * - :php:`MongoCode ` + * - MongoCode - :php:`MongoDB\\BSON\\Javascript ` - :php:`MongoDB\\BSON\\JavascriptInterface ` - * - :php:`MongoDate ` + * - MongoDate - :php:`MongoDB\\BSON\\UTCDateTime ` - :php:`MongoDB\\BSON\\UTCDateTimeInterface ` - * - :php:`MongoRegex ` + * - MongoRegex - :php:`MongoDB\\BSON\\Regex ` - :php:`MongoDB\\BSON\\RegexInterface ` - * - :php:`MongoBinData ` + * - MongoBinData - :php:`MongoDB\\BSON\\Binary ` - :php:`MongoDB\\BSON\\BinaryInterface ` - * - :php:`MongoInt32 ` + * - MongoInt32 - Not implemented. [1]_ - - * - :php:`MongoInt64 ` + * - MongoInt64 - :php:`MongoDB\\BSON\\Int64 ` - Not implemented. [2]_ - * - :php:`MongoDBRef ` + * - MongoDBRef - Not implemented. [3]_ - - * - :php:`MongoMinKey ` + * - MongoMinKey - :php:`MongoDB\\BSON\\MinKey ` - :php:`MongoDB\\BSON\\MinKeyInterface ` - * - :php:`MongoMaxKey ` + * - MongoMaxKey - :php:`MongoDB\\BSON\\MaxKey ` - :php:`MongoDB\\BSON\\MaxKeyInterface ` - * - :php:`MongoTimestamp ` + * - MongoTimestamp - :php:`MongoDB\\BSON\\Timestamp ` - :php:`MongoDB\\BSON\\TimestampInterface ` -.. [1] The new driver does not implement an equivalent class for - :php:`MongoInt32 `. When decoding BSON, 32-bit integers will - always be represented as a PHP integer. When encoding BSON, PHP integers will - encode as either a 32-bit or 64-bit integer depending on their value. +.. [1] The new driver does not implement an equivalent class for MongoInt32. + When decoding BSON, 32-bit integers will always be represented as a PHP + integer. When encoding BSON, PHP integers will encode as either a 32-bit or + 64-bit integer depending on their value. .. [2] :php:`MongoDB\\BSON\\Int64 ` does not have an interface defined. The new driver does not allow applications to instantiate @@ -99,12 +97,11 @@ the new driver. BSON decoding when a 64-bit integer cannot be represented as a PHP integer on a 32-bit platform. -.. [3] The new driver does not implement an equivalent class for - :php:`MongoDBRef ` since - :manual:`DBRefs ` are merely a BSON document - with a particular structure and not a proper BSON type. The new driver also - does not provide any helpers for working with DBRef objects, since their use - is not encouraged. +.. [3] The new driver does not implement an equivalent class for MongoDBRef + since :manual:`DBRefs ` are merely a BSON + document with a particular structure and not a proper BSON type. The new + driver also does not provide any helpers for working with DBRef objects, + since their use is not encouraged. Collection API -------------- @@ -116,15 +113,13 @@ and `Index Management `_ specifications. Although some method names have changed in accordance with the new specifications, the new class provides the same functionality as the legacy -driver's :php:`MongoCollection ` class with some notable -exceptions. +driver's MongoCollection class with some notable exceptions. A guiding principle in designing the new APIs was that explicit method names are preferable to overloaded terms found in the old API. For instance, -:php:`MongoCollection::save() ` and -:php:`MongoCollection::findAndModify() ` -have different modes of operation, depending on their arguments. Methods were -also split to distinguish between :manual:`updating specific fields +``MongoCollection::save()`` and ``MongoCollection::findAndModify()`` have +different modes of operation, depending on their arguments. Methods were also +split to distinguish between :manual:`updating specific fields ` and :manual:`full-document replacement `. @@ -134,116 +129,115 @@ equivalent method(s) in the new driver. .. list-table:: :header-rows: 1 - * - :php:`MongoCollection ` method + * - MongoCollection method - :phpclass:`MongoDB\\Collection` method(s) - * - :php:`MongoCollection::aggregate() ` + * - ``MongoCollection::aggregate()`` - :phpmethod:`MongoDB\\Collection::aggregate()` - * - :php:`MongoCollection::aggregateCursor() ` + * - ``MongoCollection::aggregateCursor()`` - :phpmethod:`MongoDB\\Collection::aggregate()` - * - :php:`MongoCollection::batchInsert() ` + * - ``MongoCollection::batchInsert()`` - :phpmethod:`MongoDB\\Collection::insertMany()` - * - :php:`MongoCollection::count() ` + * - ``MongoCollection::count()`` - :phpmethod:`MongoDB\\Collection::count()` - * - :php:`MongoCollection::createDBRef() ` + * - ``MongoCollection::createDBRef()`` - Not yet implemented. [3]_ - * - :php:`MongoCollection::createIndex() ` + * - ``MongoCollection::createIndex()`` - :phpmethod:`MongoDB\\Collection::createIndex()` - * - :php:`MongoCollection::deleteIndex() ` + * - ``MongoCollection::deleteIndex()`` - :phpmethod:`MongoDB\\Collection::dropIndex()` - * - :php:`MongoCollection::deleteIndexes() ` + * - ``MongoCollection::deleteIndexes()`` - :phpmethod:`MongoDB\\Collection::dropIndexes()` - * - :php:`MongoCollection::drop() ` + * - ``MongoCollection::drop()`` - :phpmethod:`MongoDB\\Collection::drop()` - * - :php:`MongoCollection::distinct() ` + * - ``MongoCollection::distinct()`` - :phpmethod:`MongoDB\\Collection::distinct()` - * - :php:`MongoCollection::ensureIndex() ` + * - ``MongoCollection::ensureIndex()`` - :phpmethod:`MongoDB\\Collection::createIndex()` - * - :php:`MongoCollection::find() ` + * - ``MongoCollection::find()`` - :phpmethod:`MongoDB\\Collection::find()` - * - :php:`MongoCollection::findAndModify() ` + * - ``MongoCollection::findAndModify()`` - :phpmethod:`MongoDB\\Collection::findOneAndDelete()`, :phpmethod:`MongoDB\\Collection::findOneAndReplace()`, and :phpmethod:`MongoDB\\Collection::findOneAndUpdate()` - * - :php:`MongoCollection::findOne() ` + * - ``MongoCollection::findOne()`` - :phpmethod:`MongoDB\\Collection::findOne()` - * - :php:`MongoCollection::getDBRef() ` + * - ``MongoCollection::getDBRef()`` - Not implemented. [3]_ - * - :php:`MongoCollection::getIndexInfo() ` + * - ``MongoCollection::getIndexInfo()`` - :phpmethod:`MongoDB\\Collection::listIndexes()` - * - :php:`MongoCollection::getName() ` + * - ``MongoCollection::getName()`` - :phpmethod:`MongoDB\\Collection::getCollectionName()` - * - :php:`MongoCollection::getReadPreference() ` - - Not implemented. + * - ``MongoCollection::getReadPreference()`` + - :phpmethod:`MongoDB\\Collection::getReadPreference()` - * - :php:`MongoCollection::getSlaveOkay() ` + * - ``MongoCollection::getSlaveOkay()`` - Not implemented. - * - :php:`MongoCollection::getWriteConcern() ` - - Not implemented. + * - ``MongoCollection::getWriteConcern()`` + - :phpmethod:`MongoDB\\Collection::getWriteConcern()` - * - :php:`MongoCollection::group() ` + * - ``MongoCollection::group()`` - Not implemented. Use :phpmethod:`MongoDB\\Database::command()`. See `Group Command Helper`_ for an example. - * - :php:`MongoCollection::insert() ` + * - ``MongoCollection::insert()`` - :phpmethod:`MongoDB\\Collection::insertOne()` - * - :php:`MongoCollection::parallelCollectionScan() ` + * - ``MongoCollection::parallelCollectionScan()`` - Not implemented. - * - :php:`MongoCollection::remove() ` + * - ``MongoCollection::remove()`` - :phpmethod:`MongoDB\\Collection::deleteMany()` and :phpmethod:`MongoDB\\Collection::deleteOne()` - * - :php:`MongoCollection::save() ` + * - ``MongoCollection::save()`` - :phpmethod:`MongoDB\\Collection::insertOne()` or :phpmethod:`MongoDB\\Collection::replaceOne()` with the ``upsert`` option. - * - :php:`MongoCollection::setReadPreference() ` + * - ``MongoCollection::setReadPreference()`` - Not implemented. Use :phpmethod:`MongoDB\\Collection::withOptions()`. - * - :php:`MongoCollection::setSlaveOkay() ` + * - ``MongoCollection::setSlaveOkay()`` - Not implemented. - * - :php:`MongoCollection::setWriteConcern() ` + * - ``MongoCollection::setWriteConcern()`` - Not implemented. Use :phpmethod:`MongoDB\\Collection::withOptions()`. - * - :php:`MongoCollection::update() ` + * - ``MongoCollection::update()`` - :phpmethod:`MongoDB\\Collection::replaceOne()`, :phpmethod:`MongoDB\\Collection::updateMany()`, and :phpmethod:`MongoDB\\Collection::updateOne()`. - * - :php:`MongoCollection::validate() ` + * - ``MongoCollection::validate()`` - Not implemented. Accessing IDs of Inserted Documents ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the legacy driver, :php:`MongoCollection::insert() `, -:php:`MongoCollection::batchInsert() `, and -:php:`MongoCollection::save() ` (when inserting) would -modify their input argument by injecting an ``_id`` key with a generated -ObjectId (i.e. :php:`MongoId ` object). This behavior was a bit -of a hack, as it did not rely on the argument being :php:`passed by reference +In the legacy driver, ``MongoCollection::insert()``, +``MongoCollection::batchInsert()``, and ``MongoCollection::save()`` (when +inserting) would modify their input argument by injecting an ``_id`` key with a +generated ObjectId (i.e. MongoId object). This behavior was a bit of a hack, as +it did not rely on the argument being :php:`passed by reference `; instead, it directly modified memory through the extension API and could not be implemented in PHP userland. As such, it is no longer done in the new driver and library. @@ -261,17 +255,16 @@ following methods on the write result objects: Bulk Write Operations ~~~~~~~~~~~~~~~~~~~~~ -The legacy driver's :php:`MongoWriteBatch ` classes have -been replaced with a general-purpose -:phpmethod:`MongoDB\\Collection::bulkWrite()` method. Whereas the legacy driver -only allowed bulk operations of the same type, the new method allows operations -to be mixed (e.g. inserts, updates, and deletes). +The legacy driver's MongoWriteBatch classes have been replaced with a +general-purpose :phpmethod:`MongoDB\\Collection::bulkWrite()` method. Whereas +the legacy driver only allowed bulk operations of the same type, the new method +allows operations to be mixed (e.g. inserts, updates, and deletes). MongoCollection::save() Removed ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -:php:`MongoCollection::save() `, which was syntactic sugar -for an insert or upsert operation, has been removed in favor of explicitly using +``MongoCollection::save()``, which was syntactic sugar for an insert or upsert +operation, has been removed in favor of explicitly using :phpmethod:`MongoDB\\Collection::insertOne` or :phpmethod:`MongoDB\\Collection::replaceOne` (with the ``upsert`` option). From a2f3937c8df5ec48408a02e6119e6c6b31233f47 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 30 Nov 2021 18:21:15 -0500 Subject: [PATCH 096/321] PHPLIB-721: Aggregate allowDiskUse option should be unset by default (#873) --- ...s-MongoDBCollection-method-find-option.yaml | 3 +-- docs/includes/apiargs-aggregate-option.yaml | 3 +-- src/Operation/Aggregate.php | 13 ++++--------- src/Operation/Find.php | 2 +- tests/Operation/AggregateFunctionalTest.php | 18 ++++++++++++++++++ tests/Operation/AggregateTest.php | 2 +- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml index d6ff4c532..7e298924d 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml @@ -51,8 +51,7 @@ name: allowDiskUse type: boolean description: | Enables writing to temporary files. When set to ``true``, queries can write - data to the ``_tmp`` sub-directory in the ``dbPath`` directory. The default is - ``false``. + data to the ``_tmp`` sub-directory in the ``dbPath`` directory. interface: phpmethod operation: ~ optional: true diff --git a/docs/includes/apiargs-aggregate-option.yaml b/docs/includes/apiargs-aggregate-option.yaml index 7e61ff82c..274540449 100644 --- a/docs/includes/apiargs-aggregate-option.yaml +++ b/docs/includes/apiargs-aggregate-option.yaml @@ -3,8 +3,7 @@ name: allowDiskUse type: boolean description: | Enables writing to temporary files. When set to ``true``, aggregation stages - can write data to the ``_tmp`` sub-directory in the ``dbPath`` directory. The - default is ``false``. + can write data to the ``_tmp`` sub-directory in the ``dbPath`` directory. interface: phpmethod operation: ~ optional: true diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 25c1badfa..7459481ef 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -89,7 +89,7 @@ class Aggregate implements Executable, Explainable * * * allowDiskUse (boolean): Enables writing to temporary files. When set * to true, aggregation stages can write data to the _tmp sub-directory - * in the dbPath directory. The default is false. + * in the dbPath directory. * * * batchSize (integer): The number of documents to return per batch. * @@ -179,12 +179,9 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr $expectedIndex += 1; } - $options += [ - 'allowDiskUse' => false, - 'useCursor' => true, - ]; + $options += ['useCursor' => true]; - if (! is_bool($options['allowDiskUse'])) { + if (isset($options['allowDiskUse']) && ! is_bool($options['allowDiskUse'])) { throw InvalidArgumentException::invalidType('"allowDiskUse" option', $options['allowDiskUse'], 'boolean'); } @@ -363,8 +360,6 @@ private function createCommandDocument(Server $server): array 'pipeline' => $this->pipeline, ]; - $cmd['allowDiskUse'] = $this->options['allowDiskUse']; - if ( ! empty($this->options['bypassDocumentValidation']) && server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) @@ -372,7 +367,7 @@ private function createCommandDocument(Server $server): array $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; } - foreach (['comment', 'explain', 'maxTimeMS'] as $option) { + foreach (['allowDiskUse', 'comment', 'explain', 'maxTimeMS'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/src/Operation/Find.php b/src/Operation/Find.php index e2178c01a..0acfa3ae3 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -79,7 +79,7 @@ class Find implements Executable, Explainable * * * allowDiskUse (boolean): Enables writing to temporary files. When set * to true, queries can write data to the _tmp sub-directory in the - * dbPath directory. The default is false. + * dbPath directory. * * * allowPartialResults (boolean): Get partial results from a mongos if * some shards are inaccessible (instead of throwing an error). diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php index d6b75522a..f9d895255 100644 --- a/tests/Operation/AggregateFunctionalTest.php +++ b/tests/Operation/AggregateFunctionalTest.php @@ -18,6 +18,24 @@ class AggregateFunctionalTest extends FunctionalTestCase { + public function testAllowDiskUseIsOmittedByDefault(): void + { + (new CommandObserver())->observe( + function (): void { + $operation = new Aggregate( + $this->getDatabaseName(), + $this->getCollectionName(), + [['$match' => ['x' => 1]]] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function (array $event): void { + $this->assertObjectNotHasAttribute('allowDiskUse', $event['started']->getCommand()); + } + ); + } + public function testBatchSizeIsIgnoredIfPipelineIncludesOutStage(): void { (new CommandObserver())->observe( diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php index c7ecf0edb..8050f5dd3 100644 --- a/tests/Operation/AggregateTest.php +++ b/tests/Operation/AggregateTest.php @@ -27,7 +27,7 @@ public function provideInvalidConstructorOptions() { $options = []; - foreach ($this->getInvalidBooleanValues(true) as $value) { + foreach ($this->getInvalidBooleanValues() as $value) { $options[][] = ['allowDiskUse' => $value]; } From 6bfc544818b4f78cc88a62e136bd880ea0e4ca66 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 1 Dec 2021 09:32:52 -0500 Subject: [PATCH 097/321] PHPLIB-766: Fix deprecation notices for PHP 8.1 (#874) * Avoid calling strlen() on non-strings * Add return types to Iterator implementation * Make parameters required in tests Those arguments are always passed by the data providers. * Avoid passing objects to key() * Add missing ReturnTypeWillChange attribute to Iterator classes These were likely missed in 27f664895815335a6f95083329973f7f167f279e Co-authored-by: Fran Moreno --- src/Collection.php | 4 ++-- src/Database.php | 2 +- src/Model/CollectionInfoCommandIterator.php | 2 ++ src/Model/IndexInfoIteratorIterator.php | 2 ++ tests/FunctionalTestCase.php | 2 +- tests/Model/BSONIteratorTest.php | 2 +- tests/Model/CachingIteratorTest.php | 6 +++--- tests/Operation/AggregateFunctionalTest.php | 4 ++-- tests/Operation/FindAndModifyFunctionalTest.php | 2 +- tests/Operation/MapReduceFunctionalTest.php | 4 ++-- tests/SpecTests/AtlasDataLakeSpecTest.php | 2 +- tests/SpecTests/ClientSideEncryptionSpecTest.php | 2 +- tests/SpecTests/CommandExpectations.php | 2 +- tests/SpecTests/ReadWriteConcernSpecTest.php | 2 +- tests/SpecTests/RetryableReadsSpecTest.php | 2 +- tests/SpecTests/RetryableWritesSpecTest.php | 2 +- tests/SpecTests/TransactionsSpecTest.php | 6 +++--- tests/UnifiedSpecTests/ExpectedError.php | 2 +- 18 files changed, 27 insertions(+), 23 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index e6976c608..dc6ba776b 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -140,11 +140,11 @@ class Collection */ public function __construct(Manager $manager, $databaseName, $collectionName, array $options = []) { - if (strlen($databaseName) < 1) { + if (strlen((string) $databaseName) < 1) { throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); } - if (strlen($collectionName) < 1) { + if (strlen((string) $collectionName) < 1) { throw new InvalidArgumentException('$collectionName is invalid: ' . $collectionName); } diff --git a/src/Database.php b/src/Database.php index 8f050341a..286cf970d 100644 --- a/src/Database.php +++ b/src/Database.php @@ -114,7 +114,7 @@ class Database */ public function __construct(Manager $manager, $databaseName, array $options = []) { - if (strlen($databaseName) < 1) { + if (strlen((string) $databaseName) < 1) { throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); } diff --git a/src/Model/CollectionInfoCommandIterator.php b/src/Model/CollectionInfoCommandIterator.php index 662e44809..4bb32dc12 100644 --- a/src/Model/CollectionInfoCommandIterator.php +++ b/src/Model/CollectionInfoCommandIterator.php @@ -18,6 +18,7 @@ namespace MongoDB\Model; use IteratorIterator; +use ReturnTypeWillChange; use Traversable; /** @@ -53,6 +54,7 @@ public function __construct(Traversable $iterator, $databaseName = null) * @see http://php.net/iterator.current * @return CollectionInfo */ + #[ReturnTypeWillChange] public function current() { $info = parent::current(); diff --git a/src/Model/IndexInfoIteratorIterator.php b/src/Model/IndexInfoIteratorIterator.php index 1e1bd1f28..84a5b9541 100644 --- a/src/Model/IndexInfoIteratorIterator.php +++ b/src/Model/IndexInfoIteratorIterator.php @@ -18,6 +18,7 @@ namespace MongoDB\Model; use IteratorIterator; +use ReturnTypeWillChange; use Traversable; use function array_key_exists; @@ -57,6 +58,7 @@ public function __construct(Traversable $iterator, $ns = null) * @see http://php.net/iterator.current * @return IndexInfo */ + #[ReturnTypeWillChange] public function current() { $info = parent::current(); diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 00a1b712e..2dd2d6ee3 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -267,7 +267,7 @@ public function configureFailPoint($command, ?Server $server = null): void throw new InvalidArgumentException('$command is not an array or stdClass instance'); } - if (key($command) !== 'configureFailPoint') { + if (key((array) $command) !== 'configureFailPoint') { throw new InvalidArgumentException('$command is not a configureFailPoint command'); } diff --git a/tests/Model/BSONIteratorTest.php b/tests/Model/BSONIteratorTest.php index e20b9d2cb..69c2f9d26 100644 --- a/tests/Model/BSONIteratorTest.php +++ b/tests/Model/BSONIteratorTest.php @@ -17,7 +17,7 @@ class BSONIteratorTest extends TestCase /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testValidValues(?array $typeMap = null, $binaryString, array $expectedDocuments): void + public function testValidValues(?array $typeMap, $binaryString, array $expectedDocuments): void { $bsonIt = new BSONIterator($binaryString, ['typeMap' => $typeMap]); diff --git a/tests/Model/CachingIteratorTest.php b/tests/Model/CachingIteratorTest.php index e3057ca43..1ba09039f 100644 --- a/tests/Model/CachingIteratorTest.php +++ b/tests/Model/CachingIteratorTest.php @@ -122,7 +122,7 @@ public function testWithWrongIterator(): void /** @var int */ private $i = 0; - public function current() + public function current(): int { return $this->i; } @@ -132,12 +132,12 @@ public function next(): void $this->i++; } - public function key() + public function key(): int { return $this->i; } - public function valid() + public function valid(): bool { return $this->i == 0; } diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php index f9d895255..40a70f674 100644 --- a/tests/Operation/AggregateFunctionalTest.php +++ b/tests/Operation/AggregateFunctionalTest.php @@ -170,7 +170,7 @@ function (array $event): void { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOption(?array $typeMap = null, array $expectedDocuments): void + public function testTypeMapOption(?array $typeMap, array $expectedDocuments): void { $this->createFixtures(3); @@ -185,7 +185,7 @@ public function testTypeMapOption(?array $typeMap = null, array $expectedDocumen /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOptionWithoutCursor(?array $typeMap = null, array $expectedDocuments): void + public function testTypeMapOptionWithoutCursor(?array $typeMap, array $expectedDocuments): void { if (version_compare($this->getServerVersion(), '3.6.0', '>=')) { $this->markTestSkipped('Aggregations with useCursor == false are not supported'); diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index 7d976da40..5f9902e51 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -162,7 +162,7 @@ function (array $event): void { /** * @dataProvider provideTypeMapOptionsAndExpectedDocument */ - public function testTypeMapOption(?array $typeMap = null, $expectedDocument): void + public function testTypeMapOption(?array $typeMap, $expectedDocument): void { $this->createFixtures(1); diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index 17628e382..9d36a5b34 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -235,7 +235,7 @@ function (array $event): void { /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOptionWithInlineResults(?array $typeMap = null, array $expectedDocuments): void + public function testTypeMapOptionWithInlineResults(?array $typeMap, array $expectedDocuments): void { $this->createFixtures(3); @@ -282,7 +282,7 @@ public function provideTypeMapOptionsAndExpectedDocuments() /** * @dataProvider provideTypeMapOptionsAndExpectedDocuments */ - public function testTypeMapOptionWithOutputCollection(?array $typeMap = null, array $expectedDocuments): void + public function testTypeMapOptionWithOutputCollection(?array $typeMap, array $expectedDocuments): void { $this->createFixtures(3); diff --git a/tests/SpecTests/AtlasDataLakeSpecTest.php b/tests/SpecTests/AtlasDataLakeSpecTest.php index 901ac860e..897a7332d 100644 --- a/tests/SpecTests/AtlasDataLakeSpecTest.php +++ b/tests/SpecTests/AtlasDataLakeSpecTest.php @@ -58,7 +58,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testAtlasDataLake(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + public function testAtlasDataLake(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset($runOn)) { $this->checkServerRequirements($runOn); diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 00fbee5a5..dabee3cc2 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -79,7 +79,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testClientSideEncryption(stdClass $test, ?array $runOn = null, array $data, ?array $keyVaultData = null, $jsonSchema = null, ?string $databaseName = null, ?string $collectionName = null): void + public function testClientSideEncryption(stdClass $test, ?array $runOn, array $data, ?array $keyVaultData = null, $jsonSchema = null, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index 8575eb8fe..6f44e72e3 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -48,7 +48,7 @@ class CommandExpectations implements CommandSubscriber private function __construct(array $events) { foreach ($events as $event) { - switch (key($event)) { + switch (key((array) $event)) { case 'command_failed_event': // phpcs:ignore Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps $this->expectedEvents[] = [$event->command_failed_event, CommandFailedEvent::class]; diff --git a/tests/SpecTests/ReadWriteConcernSpecTest.php b/tests/SpecTests/ReadWriteConcernSpecTest.php index 199a93ea4..96a4f7ec6 100644 --- a/tests/SpecTests/ReadWriteConcernSpecTest.php +++ b/tests/SpecTests/ReadWriteConcernSpecTest.php @@ -45,7 +45,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testReadWriteConcern(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + public function testReadWriteConcern(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); diff --git a/tests/SpecTests/RetryableReadsSpecTest.php b/tests/SpecTests/RetryableReadsSpecTest.php index 1498a34b2..3c5de4e06 100644 --- a/tests/SpecTests/RetryableReadsSpecTest.php +++ b/tests/SpecTests/RetryableReadsSpecTest.php @@ -53,7 +53,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @group matrix-testing-exclude-server-4.4-driver-4.2 * @group matrix-testing-exclude-server-5.0-driver-4.2 */ - public function testRetryableReads(stdClass $test, ?array $runOn = null, $data, string $databaseName, ?string $collectionName, ?string $bucketName): void + public function testRetryableReads(stdClass $test, ?array $runOn, $data, string $databaseName, ?string $collectionName, ?string $bucketName): void { if (isset($runOn)) { $this->checkServerRequirements($runOn); diff --git a/tests/SpecTests/RetryableWritesSpecTest.php b/tests/SpecTests/RetryableWritesSpecTest.php index a709806db..bdbb3b293 100644 --- a/tests/SpecTests/RetryableWritesSpecTest.php +++ b/tests/SpecTests/RetryableWritesSpecTest.php @@ -24,7 +24,7 @@ class RetryableWritesSpecTest extends FunctionalTestCase * @param array $runOn Top-level "runOn" array with server requirements * @param array $data Top-level "data" array to initialize collection */ - public function testRetryableWrites(stdClass $test, ?array $runOn = null, array $data): void + public function testRetryableWrites(stdClass $test, ?array $runOn, array $data): void { if ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('Transaction numbers are only allowed on a replica set member or mongos (PHPC-1415)'); diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index b50519e21..d4c40cf76 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -114,7 +114,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @dataProvider provideTransactionsTests * @group serverless */ - public function testTransactions(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + public function testTransactions(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void { $this->runTransactionTest($test, $runOn, $data, $databaseName, $collectionName); } @@ -127,7 +127,7 @@ public function provideTransactionsTests(): array /** * @dataProvider provideTransactionsConvenientApiTests */ - public function testTransactionsConvenientApi(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + public function testTransactionsConvenientApi(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void { $this->runTransactionTest($test, $runOn, $data, $databaseName, $collectionName); } @@ -146,7 +146,7 @@ public function provideTransactionsConvenientApiTests(): array * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - private function runTransactionTest(stdClass $test, ?array $runOn = null, array $data, ?string $databaseName = null, ?string $collectionName = null): void + private function runTransactionTest(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index f6e82cd70..bb55b3c4f 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -68,7 +68,7 @@ final class ExpectedError /** @var ExpectedResult|null */ private $expectedResult; - public function __construct(?stdClass $o = null, EntityMap $entityMap) + public function __construct(?stdClass $o, EntityMap $entityMap) { if ($o === null) { return; From 44c4ae4f4d50a4a80d3c712c71566e7ac4a65cd9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 1 Dec 2021 09:42:55 -0500 Subject: [PATCH 098/321] PHPLIB-764: Update estimatedDocumentCount test for Atlas Data Lake Synced with mongodb/specifications@6583f47d8f732ed7f0ca80648c88772232b2f2fc --- .../estimatedDocumentCount.json | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json b/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json index d039a51f0..87b385208 100644 --- a/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json +++ b/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json @@ -15,8 +15,25 @@ { "command_started_event": { "command": { - "count": "driverdata" - } + "aggregate": "driverdata", + "pipeline": [ + { + "$collStats": { + "count": {} + } + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": "$count" + } + } + } + ] + }, + "command_name": "aggregate", + "database_name": "test" } } ] From 40f231d5f17cecb10f1747a2557d3b0f7ae01f18 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 1 Dec 2021 09:44:27 -0500 Subject: [PATCH 099/321] PHPLIB-755: Update retryable writes and transaction tests with error labels Synced with mongodb/specifications@564547496b60c1f013c1a2edc27dd690f57ba04c --- .../bulkWrite-serverErrors.json | 8 ++-- .../deleteOne-serverErrors.json | 8 ++-- .../findOneAndDelete-serverErrors.json | 8 ++-- .../findOneAndReplace-serverErrors.json | 8 ++-- .../findOneAndUpdate-serverErrors.json | 8 ++-- .../insertMany-serverErrors.json | 8 ++-- .../insertOne-serverErrors.json | 40 +++++++++---------- .../replaceOne-serverErrors.json | 8 ++-- .../updateOne-serverErrors.json | 8 ++-- .../SpecTests/transactions/error-labels.json | 8 ++-- .../transactions/mongos-recovery-token.json | 8 ++-- .../transactions/retryable-abort.json | 24 +++++------ .../transactions/retryable-commit.json | 24 +++++------ 13 files changed, 84 insertions(+), 84 deletions(-) diff --git a/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json b/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json index 9d792ceaf..1e6cc74c0 100644 --- a/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json +++ b/tests/SpecTests/retryable-writes/bulkWrite-serverErrors.json @@ -119,12 +119,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json b/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json index 4eab2fa29..a1a27838d 100644 --- a/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/deleteOne-serverErrors.json @@ -75,12 +75,12 @@ "failCommands": [ "delete" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json b/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json index 4c1086161..c18b63f45 100644 --- a/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json +++ b/tests/SpecTests/retryable-writes/findOneAndDelete-serverErrors.json @@ -81,12 +81,12 @@ "failCommands": [ "findAndModify" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json b/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json index 64c69e2f6..944a3af84 100644 --- a/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json +++ b/tests/SpecTests/retryable-writes/findOneAndReplace-serverErrors.json @@ -85,12 +85,12 @@ "failCommands": [ "findAndModify" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json b/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json index 9f5460499..e83a61061 100644 --- a/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json +++ b/tests/SpecTests/retryable-writes/findOneAndUpdate-serverErrors.json @@ -86,12 +86,12 @@ "failCommands": [ "findAndModify" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/insertMany-serverErrors.json b/tests/SpecTests/retryable-writes/insertMany-serverErrors.json index 7b45b506c..fe8dbf4a6 100644 --- a/tests/SpecTests/retryable-writes/insertMany-serverErrors.json +++ b/tests/SpecTests/retryable-writes/insertMany-serverErrors.json @@ -92,12 +92,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/insertOne-serverErrors.json b/tests/SpecTests/retryable-writes/insertOne-serverErrors.json index e8571f8cf..5179a6ab7 100644 --- a/tests/SpecTests/retryable-writes/insertOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/insertOne-serverErrors.json @@ -761,12 +761,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 11600, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, @@ -812,12 +812,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 11602, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, @@ -863,12 +863,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 189, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, @@ -914,12 +914,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, @@ -965,12 +965,12 @@ "failCommands": [ "insert" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json b/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json index 7457228cd..6b35722e1 100644 --- a/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/replaceOne-serverErrors.json @@ -85,12 +85,12 @@ "failCommands": [ "update" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/retryable-writes/updateOne-serverErrors.json b/tests/SpecTests/retryable-writes/updateOne-serverErrors.json index 116019801..cf274f57e 100644 --- a/tests/SpecTests/retryable-writes/updateOne-serverErrors.json +++ b/tests/SpecTests/retryable-writes/updateOne-serverErrors.json @@ -86,12 +86,12 @@ "failCommands": [ "update" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/transactions/error-labels.json b/tests/SpecTests/transactions/error-labels.json index a57f216b9..0be19c731 100644 --- a/tests/SpecTests/transactions/error-labels.json +++ b/tests/SpecTests/transactions/error-labels.json @@ -963,12 +963,12 @@ "failCommands": [ "commitTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } }, diff --git a/tests/SpecTests/transactions/mongos-recovery-token.json b/tests/SpecTests/transactions/mongos-recovery-token.json index 02c2002f7..da4e9861d 100644 --- a/tests/SpecTests/transactions/mongos-recovery-token.json +++ b/tests/SpecTests/transactions/mongos-recovery-token.json @@ -180,12 +180,12 @@ "failCommands": [ "commitTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errmsg": "Replication is being shut down", - "errorLabels": [ - "RetryableWriteError" - ] + "errmsg": "Replication is being shut down" } } } diff --git a/tests/SpecTests/transactions/retryable-abort.json b/tests/SpecTests/transactions/retryable-abort.json index b712e8086..13cc7c88f 100644 --- a/tests/SpecTests/transactions/retryable-abort.json +++ b/tests/SpecTests/transactions/retryable-abort.json @@ -1556,11 +1556,11 @@ "failCommands": [ "abortTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 11600, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } @@ -1673,11 +1673,11 @@ "failCommands": [ "abortTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 11602, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } @@ -1790,11 +1790,11 @@ "failCommands": [ "abortTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 189, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } @@ -1907,11 +1907,11 @@ "failCommands": [ "abortTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } diff --git a/tests/SpecTests/transactions/retryable-commit.json b/tests/SpecTests/transactions/retryable-commit.json index d83a1d9f5..49148c62d 100644 --- a/tests/SpecTests/transactions/retryable-commit.json +++ b/tests/SpecTests/transactions/retryable-commit.json @@ -1855,11 +1855,11 @@ "failCommands": [ "commitTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 11600, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } @@ -1977,11 +1977,11 @@ "failCommands": [ "commitTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 11602, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } @@ -2099,11 +2099,11 @@ "failCommands": [ "commitTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 189, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } @@ -2221,11 +2221,11 @@ "failCommands": [ "commitTransaction" ], + "errorLabels": [ + "RetryableWriteError" + ], "writeConcernError": { "code": 91, - "errorLabels": [ - "RetryableWriteError" - ], "errmsg": "Replication is being shut down" } } From 9e0da590ec94e8af9a0ee065294627ffaee6244e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 6 Dec 2021 16:42:33 -0500 Subject: [PATCH 100/321] PHPLIB-760: Force primary for $out/$merge if any servers are pre-5.0 (#876) --- src/Collection.php | 21 ++----------- src/Database.php | 21 ++----------- src/functions.php | 73 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 36 deletions(-) diff --git a/src/Collection.php b/src/Collection.php index e6976c608..a583f613c 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -87,9 +87,6 @@ class Collection /** @var integer */ private static $wireVersionForReadConcernWithWriteStage = 8; - /** @var integer */ - private static $wireVersionForSecondarySupportsWriteStage = 13; - /** @var string */ private $collectionName; @@ -228,21 +225,9 @@ public function aggregate(array $pipeline, array $options = []) $options['readPreference'] = $this->readPreference; } - $server = select_server($this->manager, $options); - - /* If a write stage is being used with a read preference (explicit or - * inherited), check that the wire version supports it. If not, force a - * primary read preference and select a new server if necessary. */ - if ( - $hasWriteStage && isset($options['readPreference']) && - ! server_supports_feature($server, self::$wireVersionForSecondarySupportsWriteStage) - ) { - $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); - - if ($server->isSecondary()) { - $server = select_server($this->manager, $options); - } - } + $server = $hasWriteStage + ? select_server_for_aggregate_write_stage($this->manager, $options) + : select_server($this->manager, $options); /* MongoDB 4.2 and later supports a read concern when an $out stage is * being used, but earlier versions do not. diff --git a/src/Database.php b/src/Database.php index 8f050341a..25c857b6f 100644 --- a/src/Database.php +++ b/src/Database.php @@ -64,9 +64,6 @@ class Database /** @var integer */ private static $wireVersionForReadConcernWithWriteStage = 8; - /** @var integer */ - private static $wireVersionForSecondarySupportsWriteStage = 13; - /** @var string */ private $databaseName; @@ -209,21 +206,9 @@ public function aggregate(array $pipeline, array $options = []) $options['readPreference'] = $this->readPreference; } - $server = select_server($this->manager, $options); - - /* If a write stage is being used with a read preference (explicit or - * inherited), check that the wire version supports it. If not, force a - * primary read preference and select a new server if necessary. */ - if ( - $hasWriteStage && isset($options['readPreference']) && - ! server_supports_feature($server, self::$wireVersionForSecondarySupportsWriteStage) - ) { - $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); - - if ($server->isSecondary()) { - $server = select_server($this->manager, $options); - } - } + $server = $hasWriteStage + ? select_server_for_aggregate_write_stage($this->manager, $options) + : select_server($this->manager, $options); /* MongoDB 4.2 and later supports a read concern when an $out stage is * being used, but earlier versions do not. diff --git a/src/functions.php b/src/functions.php index 141c0b006..3c99e0424 100644 --- a/src/functions.php +++ b/src/functions.php @@ -19,6 +19,7 @@ use Exception; use MongoDB\BSON\Serializable; +use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\Manager; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\Server; @@ -42,6 +43,32 @@ use function reset; use function substr; +/** + * Check whether all servers support executing a write stage on a secondary. + * + * @internal + * @param Server[] $servers + */ +function all_servers_support_write_stage_on_secondary(array $servers): bool +{ + /* Write stages on secondaries are technically supported by FCV 4.4, but the + * CRUD spec requires all 5.0+ servers since FCV is not tracked by SDAM. */ + static $wireVersionForWriteStageOnSecondary = 13; + + foreach ($servers as $server) { + // We can assume that load balancers only front 5.0+ servers + if ($server->getType() === Server::TYPE_LOAD_BALANCER) { + continue; + } + + if (! server_supports_feature($server, $wireVersionForWriteStageOnSecondary)) { + return false; + } + } + + return true; +} + /** * Applies a type map to a document. * @@ -459,3 +486,49 @@ function select_server(Manager $manager, array $options): Server return $manager->selectServer($readPreference); } + +/** + * Performs server selection for an aggregate operation with a write stage. The + * $options parameter may be modified by reference if a primary read preference + * must be forced due to the existence of pre-5.0 servers in the topology. + * + * @internal + * @see https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#aggregation-pipelines-with-write-stages + */ +function select_server_for_aggregate_write_stage(Manager $manager, array &$options): Server +{ + $readPreference = extract_read_preference_from_options($options); + + /* If there is either no read preference or a primary read preference, there + * is no special server selection logic to apply. */ + if ($readPreference === null || $readPreference->getMode() === ReadPreference::RP_PRIMARY) { + return select_server($manager, $options); + } + + $server = null; + $serverSelectionError = null; + + try { + $server = select_server($manager, $options); + } catch (DriverRuntimeException $serverSelectionError) { + } + + /* If any pre-5.0 servers exist in the topology, force a primary read + * preference and repeat server selection if it previously failed or + * selected a secondary. */ + if (! all_servers_support_write_stage_on_secondary($manager->getServers())) { + $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY); + + if ($server === null || $server->isSecondary()) { + return select_server($manager, $options); + } + } + + /* If the topology only contains 5.0+ servers, we should either return the + * previously selected server or propagate the server selection error. */ + if ($serverSelectionError !== null) { + throw $serverSelectionError; + } + + return $server; +} From fef895def95034879f8c81fc60a76cd376fd4671 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 8 Dec 2021 19:20:50 -0500 Subject: [PATCH 101/321] PHPLIB-773: Fix GCP_PRIVATE_KEY export (#881) --- .evergreen/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index c1de0046a..7e8038455 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -244,7 +244,7 @@ functions: export AZURE_CLIENT_ID="${client_side_encryption_azure_client_id}" export AZURE_CLIENT_SECRET="${client_side_encryption_azure_client_secret}" export GCP_EMAIL="${client_side_encryption_gcp_email}" - export GCP_PRIVATEKEY="${client_side_encryption_gcp_privatekey}" + export GCP_PRIVATE_KEY="${client_side_encryption_gcp_privatekey}" export PATH="${PHP_PATH}/bin:$PATH" MOCK_SERVICE_ID=${MOCK_SERVICE_ID} API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh From 5490c089f5f50f1d513d8936bc1178769940c69c Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 14 Dec 2021 14:20:15 -0500 Subject: [PATCH 102/321] PHPLIB-768: Spec and prose tests for CSFLE KMIP support (#880) * Add missing sprintf for UnexpectedValueException message This dates back to f0870fb34b5ae4fe4d1da86ddfc965750261e2b5 and a9ab2fc237e50b9df19d50e5e6a6e4db6daa7987 * PHPLIB-768: Spec and prose tests for CSFLE KMIP support Add KMS server on Evergreen for KMIP tests. Synced with mongodb/specifications@f679da74caadf103ab372fcf8b4aa70d2d54fcd1 Temporarily update driver axis for testing against PHPC-1912. * PHPLIB-768 and PHPLIB-639: KMS TLS prose tests --- .evergreen/config.yml | 69 +- .evergreen/run-tests.sh | 3 + .../ClientSideEncryptionSpecTest.php | 350 +++- tests/SpecTests/Context.php | 31 + .../corpus/corpus-encrypted.json | 1830 +++++++++++++++++ .../corpus/corpus-key-kmip.json | 32 + .../corpus/corpus-schema.json | 1266 ++++++++++++ .../client-side-encryption/corpus/corpus.json | 1662 +++++++++++++++ .../tests/azureKMS.json | 14 + .../client-side-encryption/tests/gcpKMS.json | 14 + .../client-side-encryption/tests/kmipKMS.json | 223 ++ 11 files changed, 5483 insertions(+), 11 deletions(-) create mode 100644 tests/SpecTests/client-side-encryption/corpus/corpus-key-kmip.json create mode 100644 tests/SpecTests/client-side-encryption/tests/kmipKMS.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 7e8038455..12435875a 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -245,6 +245,12 @@ functions: export AZURE_CLIENT_SECRET="${client_side_encryption_azure_client_secret}" export GCP_EMAIL="${client_side_encryption_gcp_email}" export GCP_PRIVATE_KEY="${client_side_encryption_gcp_privatekey}" + export KMIP_ENDPOINT="${client_side_encryption_kmip_endpoint}" + export KMS_ENDPOINT_EXPIRED="${client_side_encryption_kms_endpoint_expired}" + export KMS_ENDPOINT_WRONG_HOST="${client_side_encryption_kms_endpoint_wrong_host}" + export KMS_ENDPOINT_REQUIRE_CLIENT_CERT="${client_side_encryption_kms_endpoint_require_client_cert}" + export KMS_TLS_CA_FILE="${client_side_encryption_kms_tls_ca_file}" + export KMS_TLS_CERTIFICATE_KEY_FILE="${client_side_encryption_kms_tls_certificate_key_file}" export PATH="${PHP_PATH}/bin:$PATH" MOCK_SERVICE_ID=${MOCK_SERVICE_ID} API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh @@ -341,6 +347,42 @@ functions: ${DRIVERS_TOOLS}/.evergreen/run-load-balancer.sh stop fi + "start kms servers": + - command: shell.exec + # Init venv without background:true to install dependencies + params: + script: |- + set -o errexit + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + - command: shell.exec + params: + background: true + # Use different ports for KMS HTTP servers to avoid conflicts with load balancers + script: |- + set -o errexit + cd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + python -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8100 & + python -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8101 & + python -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8102 --require_client_cert & + python -u kms_kmip_server.py --port 5698 & + - command: expansions.update + params: + updates: + - key: client_side_encryption_kms_tls_ca_file + value: ${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem + - key: client_side_encryption_kms_tls_certificate_key_file + value: ${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem + - key: client_side_encryption_kms_endpoint_expired + value: 127.0.0.1:8100 + - key: client_side_encryption_kms_endpoint_wrong_host + value: 127.0.0.1:8101 + - key: client_side_encryption_kms_endpoint_require_client_cert + value: 127.0.0.1:8102 + - key: client_side_encryption_kmip_endpoint + value: localhost:5698 + pre: - func: "fetch source" - func: "prepare resources" @@ -397,6 +439,7 @@ tasks: - func: "bootstrap mongo-orchestration" vars: TOPOLOGY: "server" + - func: "start kms servers" - func: "run tests" - name: "test-replica_set" @@ -405,6 +448,7 @@ tasks: - func: "bootstrap mongo-orchestration" vars: TOPOLOGY: "replica_set" + - func: "start kms servers" - func: "run tests" - name: "test-sharded_cluster" @@ -413,6 +457,7 @@ tasks: - func: "bootstrap mongo-orchestration" vars: TOPOLOGY: "sharded_cluster" + - func: "start kms servers" - func: "run tests" - name: "test-atlas-data-lake" @@ -428,6 +473,7 @@ tasks: TOPOLOGY: "server" AUTH: "auth" REQUIRE_API_VERSION: "yes" + - func: "start kms servers" - func: "run tests" vars: API_VERSION: "1" @@ -439,6 +485,7 @@ tasks: vars: TOPOLOGY: "server" ORCHESTRATION_FILE: "versioned-api-testing.json" + - func: "start kms servers" - func: "run tests" vars: TESTS: "versioned-api" @@ -460,6 +507,7 @@ tasks: TOPOLOGY: "sharded_cluster" SSL: "yes" - func: "start load balancer" + - func: "start kms servers" - func: "run tests" vars: # Testing with HAProxy requires service ID mocking @@ -561,20 +609,21 @@ axes: - id: driver-versions display_name: Driver Version values: + # TODO: Update references to master branch after PHPC 1.12 is released - id: "lowest-supported" - display_name: "1.11.0" + # display_name: "1.11.0" + display_name: "1.12-dev" variables: - EXTENSION_VERSION: "1.11.0" + EXTENSION_BRANCH: "master" - id: "latest-stable" - display_name: "Latest Stable (1.11.x)" - variables: - EXTENSION_VERSION: "stable" - - id: "upcoming-stable" - display_name: "1.11-dev" + # display_name: "Latest Stable (1.11.x)" + display_name: "1.12-dev" variables: - EXTENSION_BRANCH: "v1.11" + # EXTENSION_VERSION: "stable" + EXTENSION_BRANCH: "master" - id: "latest-dev" - display_name: "1.12-dev (master)" + # display_name: "1.12-dev (master)" + display_name: "1.12-dev" variables: EXTENSION_BRANCH: "master" @@ -684,7 +733,9 @@ buildvariants: matrix_spec: { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "*" } exclude_spec: # Avoid duplicate build variants from test-php-versions + - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "lowest-supported" } - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-stable" } + - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-dev" } display_name: "${os}, MongoDB ${edge-versions}, PHP ${php-versions}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index bbb8a1f44..93a574a38 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -43,6 +43,9 @@ if [ "${IS_MATRIX_TESTING}" = "true" ]; then . $DIR/install-dependencies.sh fi +# Enable verbose output to see skipped and incomplete tests +PHPUNIT_OPTS="${PHPUNIT_OPTS} -v" + # For load balancer testing, we need to enable service ID mocking if [ "${MOCK_SERVICE_ID}" = "1" ]; then PHPUNIT_OPTS="${PHPUNIT_OPTS} -d mongodb.mock_service_id=1" diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index dabee3cc2..79c82b80d 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -16,6 +16,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Operation\CreateCollection; use MongoDB\Tests\CommandObserver; +use PHPUnit\Framework\Assert; use PHPUnit\Framework\SkippedTestError; use stdClass; use Throwable; @@ -24,6 +25,7 @@ use function base64_decode; use function basename; use function file_get_contents; +use function getenv; use function glob; use function in_array; use function iterator_to_array; @@ -195,6 +197,10 @@ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey) 'azure' => Context::getAzureCredentials(), 'gcp' => Context::getGCPCredentials(), 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], + ], + 'tlsOptions' => [ + 'kmip' => Context::getKmsTlsOptions(), ], ]; @@ -300,6 +306,10 @@ public static function dataKeyProvider() 'keyName' => 'key-name-csfle', ], ], + 'kmip' => [ + 'providerName' => 'kmip', + 'masterKey' => [], + ], ]; } @@ -544,6 +554,7 @@ public function testCorpus($schemaMap = true): void $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-aws.json')), $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-azure.json')), $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-gcp.json')), + $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-kmip.json')), ]); $encryptionOpts = [ @@ -553,6 +564,10 @@ public function testCorpus($schemaMap = true): void 'azure' => Context::getAzureCredentials(), 'gcp' => Context::getGCPCredentials(), 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], + ], + 'tlsOptions' => [ + 'kmip' => Context::getKmsTlsOptions(), ], ]; @@ -578,6 +593,7 @@ public function testCorpus($schemaMap = true): void 'altname_azure', 'altname_gcp', 'altname_local', + 'altname_kmip', ]; foreach ($corpus as $fieldName => $data) { @@ -639,6 +655,10 @@ public function testCustomEndpoint(Closure $test): void 'aws' => Context::getAWSCredentials(), 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => 'login.microsoftonline.com:443'], 'gcp' => Context::getGCPCredentials() + ['endpoint' => 'oauth2.googleapis.com:443'], + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], + ], + 'tlsOptions' => [ + 'kmip' => Context::getKmsTlsOptions(), ], ]); @@ -647,6 +667,10 @@ public function testCustomEndpoint(Closure $test): void 'kmsProviders' => [ 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => 'example.com:443'], 'gcp' => Context::getGCPCredentials() + ['endpoint' => 'example.com:443'], + 'kmip' => ['endpoint' => 'doesnotexist.local:5698'], + ], + 'tlsOptions' => [ + 'kmip' => Context::getKmsTlsOptions(), ], ]); @@ -664,6 +688,7 @@ public static function customEndpointProvider() 'keyName' => 'key-name-csfle', 'endpoint' => 'cloudkms.googleapis.com:443', ]; + $kmipMasterKey = ['keyId' => '1']; yield 'Test 1' => [ static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { @@ -746,6 +771,38 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio $clientEncryption->createDataKey('gcp', ['masterKey' => $masterKey]); }, ]; + + yield 'Test 10' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($kmipMasterKey): void { + $keyId = $clientEncryption->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#doesnotexist.local#'); + $clientEncryptionInvalid->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + }, + ]; + + yield 'Test 11' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($kmipMasterKey): void { + $kmipMasterKey['endpoint'] = Context::getKmipEndpoint(); + + $keyId = $clientEncryption->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + $encrypted = $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $test->assertSame('test', $clientEncryption->decrypt($encrypted)); + }, + ]; + + yield 'Test 12' => [ + static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($kmipMasterKey): void { + $kmipMasterKey['endpoint'] = 'doesnotexist.local:5698'; + + $test->expectException(RuntimeException::class); + $test->expectExceptionMessageMatches('#doesnotexist.local#'); + $clientEncryption->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + }, + ]; } /** @@ -807,6 +864,280 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void $clientMongocryptd->selectDatabase('db')->command(['ping' => 1]); } + /** + * Prose test: Invalid KMS Certificate + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#invalid-kms-certificate + */ + public function testInvalidKmsCertificate(): void + { + $client = static::createTestClient(); + + $clientEncryption = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['aws' => Context::getAWSCredentials()], + 'tlsOptions' => ['aws' => Context::getKmsTlsOptions()], + ]); + + $this->expectException(ConnectionException::class); + // Note: this assumes an OpenSSL error message + $this->expectExceptionMessageMatches('#certificate has expired#'); + + $clientEncryption->createDataKey('aws', [ + 'masterKey' => [ + 'region' => 'us-east-1', + 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + 'endpoint' => self::getEnv('KMS_ENDPOINT_EXPIRED'), + ], + ]); + } + + /** + * Prose test: Invalid Hostname in KMS Certificate + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#invalid-hostname-in-kms-certificate + */ + public function testInvalidHostnameInKmsCertificate(): void + { + $client = static::createTestClient(); + + $clientEncryption = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['aws' => Context::getAWSCredentials()], + 'tlsOptions' => ['aws' => Context::getKmsTlsOptions()], + ]); + + $this->expectException(ConnectionException::class); + // Note: this assumes an OpenSSL error message + $this->expectExceptionMessageMatches('#IP address mismatch#'); + + $clientEncryption->createDataKey('aws', [ + 'masterKey' => [ + 'region' => 'us-east-1', + 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + 'endpoint' => self::getEnv('KMS_ENDPOINT_WRONG_HOST'), + ], + ]); + } + + /** + * Prose test: KMS TLS Options + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#kms-tls-options-tests + * @dataProvider provideKmsTlsOptionsTests + */ + public function testKmsTlsOptions(Closure $test): void + { + $client = static::createTestClient(); + + $clientEncryptionNoClientCert = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => self::getEnv('KMS_ENDPOINT_REQUIRE_CLIENT_CERT')], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => self::getEnv('KMS_ENDPOINT_REQUIRE_CLIENT_CERT')], + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], + ], + 'tlsOptions' => [ + 'aws' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'azure' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'gcp' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'kmip' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + ], + ]); + + $clientEncryptionWithTls = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => self::getEnv('KMS_ENDPOINT_REQUIRE_CLIENT_CERT')], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => self::getEnv('KMS_ENDPOINT_REQUIRE_CLIENT_CERT')], + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], + ], + 'tlsOptions' => [ + 'aws' => Context::getKmsTlsOptions(), + 'azure' => Context::getKmsTlsOptions(), + 'gcp' => Context::getKmsTlsOptions(), + 'kmip' => Context::getKmsTlsOptions(), + ], + ]); + + $clientEncryptionExpired = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => self::getEnv('KMS_ENDPOINT_EXPIRED')], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => self::getEnv('KMS_ENDPOINT_EXPIRED')], + 'kmip' => ['endpoint' => self::getEnv('KMS_ENDPOINT_EXPIRED')], + ], + 'tlsOptions' => [ + 'aws' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'azure' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'gcp' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'kmip' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + ], + ]); + + $clientEncryptionInvalidHostname = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => self::getEnv('KMS_ENDPOINT_WRONG_HOST')], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => self::getEnv('KMS_ENDPOINT_WRONG_HOST')], + 'kmip' => ['endpoint' => self::getEnv('KMS_ENDPOINT_WRONG_HOST')], + ], + 'tlsOptions' => [ + 'aws' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'azure' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'gcp' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + 'kmip' => ['tlsCAFile' => getenv('KMS_TLS_CA_FILE')], + ], + ]); + + $test($this, $clientEncryptionNoClientCert, $clientEncryptionWithTls, $clientEncryptionExpired, $clientEncryptionInvalidHostname); + } + + public static function provideKmsTlsOptionsTests() + { + $awsMasterKey = ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0']; + $azureMasterKey = ['keyVaultEndpoint' => 'doesnotexist.local', 'keyName' => 'foo']; + $gcpMasterKey = ['projectId' => 'foo', 'location' => 'bar', 'keyRing' => 'baz', 'keyName' => 'foo']; + $kmipMasterKey = []; + + // Note: expected exception messages below assume OpenSSL is used + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-1-aws + yield 'AWS: client_encryption_no_client_cert' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($awsMasterKey): void { + $test->expectException(ConnectionException::class); + // Avoid asserting exception message for failed TLS handshake since it may be inconsistent + $clientEncryptionNoClientCert->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => self::getEnv('KMS_ENDPOINT_REQUIRE_CLIENT_CERT')]]); + }, + ]; + + yield 'AWS: client_encryption_with_tls' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($awsMasterKey): void { + $test->expectException(EncryptionException::class); + $test->expectExceptionMessageMatches('#parse error#'); + $clientEncryptionWithTls->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => self::getEnv('KMS_ENDPOINT_REQUIRE_CLIENT_CERT')]]); + }, + ]; + + yield 'AWS: client_encryption_expired' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($awsMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#certificate has expired#'); + $clientEncryptionExpired->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => self::getEnv('KMS_ENDPOINT_EXPIRED')]]); + }, + ]; + + yield 'AWS: client_encryption_invalid_hostname' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($awsMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#IP address mismatch#'); + $clientEncryptionInvalidHostname->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => self::getEnv('KMS_ENDPOINT_WRONG_HOST')]]); + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-2-azure + yield 'Azure: client_encryption_no_client_cert' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($azureMasterKey): void { + $test->expectException(ConnectionException::class); + // Avoid asserting exception message for failed TLS handshake since it may be inconsistent + $clientEncryptionNoClientCert->createDataKey('azure', ['masterKey' => $azureMasterKey]); + }, + ]; + + yield 'Azure: client_encryption_with_tls' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($azureMasterKey): void { + $test->expectException(EncryptionException::class); + $test->expectExceptionMessageMatches('#HTTP status=404#'); + $clientEncryptionWithTls->createDataKey('azure', ['masterKey' => $azureMasterKey]); + }, + ]; + + yield 'Azure: client_encryption_expired' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($azureMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#certificate has expired#'); + $clientEncryptionExpired->createDataKey('azure', ['masterKey' => $azureMasterKey]); + }, + ]; + + yield 'Azure: client_encryption_invalid_hostname' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($azureMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#IP address mismatch#'); + $clientEncryptionInvalidHostname->createDataKey('azure', ['masterKey' => $azureMasterKey]); + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-3-gcp + yield 'GCP: client_encryption_no_client_cert' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($gcpMasterKey): void { + $test->expectException(ConnectionException::class); + // Avoid asserting exception message for failed TLS handshake since it may be inconsistent + $clientEncryptionNoClientCert->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); + }, + ]; + + yield 'GCP: client_encryption_with_tls' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($gcpMasterKey): void { + $test->expectException(EncryptionException::class); + $test->expectExceptionMessageMatches('#HTTP status=404#'); + $clientEncryptionWithTls->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); + }, + ]; + + yield 'GCP: client_encryption_expired' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($gcpMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#certificate has expired#'); + $clientEncryptionExpired->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); + }, + ]; + + yield 'GCP: client_encryption_invalid_hostname' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($gcpMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#IP address mismatch#'); + $clientEncryptionInvalidHostname->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-4-kmip + yield 'KMIP: client_encryption_no_client_cert' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($kmipMasterKey): void { + $test->expectException(ConnectionException::class); + // Avoid asserting exception message for failed TLS handshake since it may be inconsistent + $clientEncryptionNoClientCert->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + }, + ]; + + yield 'KMIP: client_encryption_with_tls' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($kmipMasterKey): void { + $keyId = $clientEncryptionWithTls->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + $test->assertInstanceOf(Binary::class, $keyId); + }, + ]; + + yield 'KMIP: client_encryption_expired' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($kmipMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#certificate has expired#'); + $clientEncryptionExpired->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + }, + ]; + + yield 'KMIP: client_encryption_invalid_hostname' => [ + static function (self $test, ClientEncryption $clientEncryptionNoClientCert, ClientEncryption $clientEncryptionWithTls, ClientEncryption $clientEncryptionExpired, ClientEncryption $clientEncryptionInvalidHostname) use ($kmipMasterKey): void { + $test->expectException(ConnectionException::class); + $test->expectExceptionMessageMatches('#IP address mismatch#'); + $clientEncryptionInvalidHostname->createDataKey('kmip', ['masterKey' => $kmipMasterKey]); + }, + ]; + } + /** * Casts the value for a BSON corpus structure to int64 if necessary. * @@ -862,9 +1193,13 @@ private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEnc $keyId = 'GCPAAAAAAAAAAAAAAAAAAA=='; $keyAltName = 'gcp'; break; + case 'kmip': + $keyId = 'KMIPAAAAAAAAAAAAAAAAAA=='; + $keyAltName = 'kmip'; + break; default: - throw new UnexpectedValueException('Unexpected KMS "%s"', $data->kms); + throw new UnexpectedValueException(sprintf('Unexpected KMS "%s"', $data->kms)); } switch ($data->identifier) { @@ -877,7 +1212,7 @@ private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEnc break; default: - throw new UnexpectedValueException('Unexpected value "%s" for identifier', $data->identifier); + throw new UnexpectedValueException(sprintf('Unexpected value "%s" for identifier', $data->identifier)); } if ($data->allowed) { @@ -901,6 +1236,17 @@ private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEnc return $data->value; } + private static function getEnv(string $name): string + { + $value = getenv($name); + + if ($value === false) { + Assert::markTestSkipped(sprintf('Environment variable "%s" is not defined', $name)); + } + + return $value; + } + private function insertKeyVaultData(?array $keyVaultData = null): void { $context = $this->getContext(); diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 6769c9878..286c03b65 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -123,6 +123,16 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ if (isset($autoEncryptionOptions['kmsProviders']->gcp)) { $autoEncryptionOptions['kmsProviders']->gcp = self::getGCPCredentials(); } + + if (isset($autoEncryptionOptions['kmsProviders']->kmip)) { + $autoEncryptionOptions['kmsProviders']->kmip = ['endpoint' => self::getKmipEndpoint()]; + + if (empty($autoEncryptionOptions['tlsOptions'])) { + $autoEncryptionOptions['tlsOptions'] = new stdClass(); + } + + $autoEncryptionOptions['tlsOptions']->kmip = self::getKmsTlsOptions(); + } } if (isset($test->outcome->collection->name)) { @@ -273,6 +283,27 @@ public static function getAzureCredentials(): array ]; } + public static function getKmipEndpoint(): string + { + if (! getenv('KMIP_ENDPOINT')) { + Assert::markTestSkipped('Please configure KMIP endpoint to use KMIP KMS provider.'); + } + + return getenv('KMIP_ENDPOINT'); + } + + public static function getKmsTlsOptions(): array + { + if (! getenv('KMS_TLS_CA_FILE') || ! getenv('KMS_TLS_CERTIFICATE_KEY_FILE')) { + Assert::markTestSkipped('Please configure KMS TLS options.'); + } + + return [ + 'tlsCAFile' => getenv('KMS_TLS_CA_FILE'), + 'tlsCertificateKeyFile' => getenv('KMS_TLS_CERTIFICATE_KEY_FILE'), + ]; + } + public static function getGCPCredentials(): array { if (! getenv('GCP_EMAIL') || ! getenv('GCP_PRIVATE_KEY')) { diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json b/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json index a11682688..1b72aa8a3 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-encrypted.json @@ -7681,5 +7681,1835 @@ "value": { "$maxKey": 1 } + }, + "kmip_double_rand_auto_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAB1hL/nPkpQtqxQUANbIJr30PQ98vPvaoy4JWUoElOL+cCnrSra3o7W+12dydy0rCS2EKrVm7Fw0C8L9nf1hpWjw==", + "subType": "06" + } + } + }, + "kmip_double_rand_auto_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAABxlcphy2SxXlkRBvO1Z3nNUqchmeOhIhkdYBbbW7CwYeLVRDciXFsZN73Nb9Bm+W4IpUNpo6mqFEtfjevIjtFyg==", + "subType": "06" + } + } + }, + "kmip_double_rand_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAABx5AfRSiblFc1DGwxRIaUSP2kaM76ryzPUKL9KnEgnX1kjIlFz5B15uMht2cxdrntHFe1qZZk8V9PxTBpWZhJ8Q==", + "subType": "06" + } + } + }, + "kmip_double_rand_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAABXUC9v9HPrmU9tINzFmr2sQM9f7GHDus+y5T4pWX28PRtfnTysN/ANCfB9RosoR/wuKsbznwwD2JfSzOvlKo3PQ==", + "subType": "06" + } + } + }, + "kmip_double_det_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "kmip_double_det_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.2339999999999999858" + } + }, + "kmip_string_rand_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAACGHmqW1qbfqVlfB0x0CkXCk9smhs3yXsxJ/8eypSgbDQqVLSW2nf5bbHpnoCHHNtQ7I7ZBXzPzDLH2GgMJpopeQ==", + "subType": "06" + } + } + }, + "kmip_string_rand_auto_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAC9BJTD1pEMbslAjbJYt7yx/jzKkcZF3axu96+NYwp8afUCjXG5TOUZzODOwkbJuWgr7DBxa2GkZTvaAEk86h+Ow==", + "subType": "06" + } + } + }, + "kmip_string_rand_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAACQlG28ECy8KHXC7GEPdC8+raBo2RMJwl5pofcPaTGkPUEbkreguMd1mYctNb90vXxby1nNeJY4o5zJJCMiNhNXg==", + "subType": "06" + } + } + }, + "kmip_string_rand_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAACbWuK+3nzeKSNVjmgHb0Ii7rA+CsAd+gYubPiMiHXZwE/o6i9FYWN+t/VK3p4K0CwIi6q3cycrMb2IgcvM27Q7Q==", + "subType": "06" + } + } + }, + "kmip_string_det_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAC5OZgr9keCXOIj5Fi06i4win1xt7gpsyPA4Os+HdFn1MIP9tnktvWNRb8Rqhuj2O9KO83brx74Hu3EQ4nT6uCMw==", + "subType": "06" + } + } + }, + "kmip_string_det_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAC5OZgr9keCXOIj5Fi06i4win1xt7gpsyPA4Os+HdFn1MIP9tnktvWNRb8Rqhuj2O9KO83brx74Hu3EQ4nT6uCMw==", + "subType": "06" + } + } + }, + "kmip_string_det_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAC5OZgr9keCXOIj5Fi06i4win1xt7gpsyPA4Os+HdFn1MIP9tnktvWNRb8Rqhuj2O9KO83brx74Hu3EQ4nT6uCMw==", + "subType": "06" + } + } + }, + "kmip_object_rand_auto_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAADh2nGqaAUwHDRVjqYpj8JAPH7scmiHp1Z9SGBZQ6Fapxm+zWDdTBHyitM9U69BctJ5DaaafyqFOj5yr6sJ+ebJQ==", + "subType": "06" + } + } + }, + "kmip_object_rand_auto_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAD1YhOKyNle4y0Qbeio1HlCULLeTCALCLgKSITd50bilD+oDyqQawixJAwphcdjhLdFzbFwst5RWqpsiWMPHx4hQ==", + "subType": "06" + } + } + }, + "kmip_object_rand_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAADveILoWFgX7AhUWCv8UL52TUa75qHuoNadnTQydJlqd6PVmtRKj+8vS7VwxNWPaH4wB1Tk7emMyFEbZpvvzjxqQ==", + "subType": "06" + } + } + }, + "kmip_object_rand_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAADB/LN9V/4SROJn+ESHRLM7wwcUltQUx3+LbbYXjPDXiiV14HK76Iyy6ZxJ+M5qC9bRj3afhTKuWLBblB8WwksOg==", + "subType": "06" + } + } + }, + "kmip_object_det_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_det_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_array_rand_auto_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEasWXQam8XtOkSO0nEttMCQ0iZ4V8DDmhMKyQDFDsiNHyF2h98Ya/xFv4ZSlbpGWXPBvBATEGgov/PDg2vhVi53y4Pk33RHfY60hABuksp3o=", + "subType": "06" + } + } + }, + "kmip_array_rand_auto_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEj3A1DYSEHm/3SlEmusA+pewxRPUoZ2NAjs60ioEBlCw9n6yiiB+X8d/w40TKsjZcOSfh05NC0z3gnpqQvrNolkxkvi9dmFiZeiiv5vBZUPI=", + "subType": "06" + } + } + }, + "kmip_array_rand_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEqeJW+L6lP0bn5QcD0FMI0C8vv2n5kV7SKgqKi1o5mxaxmp3Cjlspf7yumfSiQ5js6G9yJVAvHuxlqv14UFyR9RgXS0PIA8WzsAqkL0sJSw0=", + "subType": "06" + } + } + }, + "kmip_array_rand_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAEnPlPwy0B1VKuNum1GzkZwQjZia5jNYL5bf/k+PbfhnToTRWGxx8+E3R7XXp6YT/rFkjPlzU8ww9+iZNo2oqNpYuHdrIC8ybhO6HZAlvcERo=", + "subType": "06" + } + } + }, + "kmip_array_det_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_det_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_binData=00_rand_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFliNDZ6DmjoVcYQBCKDI9njpBsDELg+TD6XLF7xbZnMaJCCHLHr7w3x2/xFfrFSN44CtGAKOniYPCMAspaxHqOA==", + "subType": "06" + } + } + }, + "kmip_binData=00_rand_auto_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAF/P8LPmHKGgG0l5/Xi7jdkwfxpGPxoY0417suCvN6zjM3JNdufytzkektrm9CbBb1SnZCGYF9c0FCMzFG+tN/dg==", + "subType": "06" + } + } + }, + "kmip_binData=00_rand_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFWI0N4RbnYdEiFrzNpbRN9p+bSLm8Lthiu4K3/CvBg6GQpLMVQFhjW01Bud0lxpT2ohRnOK+ASUhiFcUU/t/lWQ==", + "subType": "06" + } + } + }, + "kmip_binData=00_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFQZvAtpY4cjEr1rJWVoUGaZKmzocSJ0muHose7Tk5kRDczjFa4Jcu4hN7JLM9qz2z4g+WJC3KQTdW4ZBXStke/Q==", + "subType": "06" + } + } + }, + "kmip_binData=00_det_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFohIHrvzu8xLxVHsnYEDhZmv8BpEoEtFSjMUQzvBLUInvvTuU/rOzlVL88CkAEII7M3hcvrz8FKY7b7lC1veoYg==", + "subType": "06" + } + } + }, + "kmip_binData=00_det_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFohIHrvzu8xLxVHsnYEDhZmv8BpEoEtFSjMUQzvBLUInvvTuU/rOzlVL88CkAEII7M3hcvrz8FKY7b7lC1veoYg==", + "subType": "06" + } + } + }, + "kmip_binData=00_det_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFohIHrvzu8xLxVHsnYEDhZmv8BpEoEtFSjMUQzvBLUInvvTuU/rOzlVL88CkAEII7M3hcvrz8FKY7b7lC1veoYg==", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFn7rhdO8tYq77uVxcqd9Qjz84Yg7JnJMYf0ULTMTh1vJHacckkhXw+8fIMMiAKwuOVwGkMAtu5RBvrFqdfxryCg8RLTxu1YYVthufiClEIS0=", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_auto_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFwwXQx9dKyoyHq7GBMmHzYe9ysoJK/f/ZWzA6nErau9MtX1gqi7VRsYqkamb47/zVbsLZwPMmdgNyPxEh3kqbV2D61t5RG2A3VeqhO1pTF8c=", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAFALeGeinJ8DE+WZniLdCIW2gfJUj445Ukp9PvRLgBXLGedl8mIXlLF2eu3BA9vP6s5y9w6peQjhn+oEofrsUVYD2duyzeIRMKgNiNchjf6TU=", + "subType": "06" + } + } + }, + "kmip_binData=04_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAF06Fx8CO3OSKE3fGri0VwK0e22YiG9LH2QkDTsRdFbT2lBm+bDD9FrEY8vKWS5RljMuysaxjBOzZ98d2LEs6k8LMOm83Nz/RESe4ZbbcfdQ0=", + "subType": "06" + } + } + }, + "kmip_binData=04_det_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFzmZI909fJgxOykJtvOlv5LsX8z6BxUX2Xg5TsIwOxJMPSC8usm/zR7sZawoVBOuJxtNVLY/8oNP/4pFtAmQo02bUOtTo1yxNz/IZa9x+Q5E=", + "subType": "06" + } + } + }, + "kmip_binData=04_det_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFzmZI909fJgxOykJtvOlv5LsX8z6BxUX2Xg5TsIwOxJMPSC8usm/zR7sZawoVBOuJxtNVLY/8oNP/4pFtAmQo02bUOtTo1yxNz/IZa9x+Q5E=", + "subType": "06" + } + } + }, + "kmip_binData=04_det_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAFzmZI909fJgxOykJtvOlv5LsX8z6BxUX2Xg5TsIwOxJMPSC8usm/zR7sZawoVBOuJxtNVLY/8oNP/4pFtAmQo02bUOtTo1yxNz/IZa9x+Q5E=", + "subType": "06" + } + } + }, + "kmip_undefined_rand_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_rand_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_objectId_rand_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAHZFzE908RuO5deEt3t2QQdT12ybwqbm8D+sMJrdKt2Wp4kVPsw4ocAGGsRYN6VXe46P5fmyG5HqVWn0hkflZnQg==", + "subType": "06" + } + } + }, + "kmip_objectId_rand_auto_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAH3dPKyCCStvOtVGzlgIS33fsl8OAwQblt9i21pOVuLiliY1Tup9EtkSic88+nNEtXnq9gRknRzLthXv/k1ql+7Q==", + "subType": "06" + } + } + }, + "kmip_objectId_rand_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAHcEjxVfHDSfLzFxAuK/rs/Pn/XV7jLkgKXZYeY0PNlRi1MHojN2AvQqI3J2rOvAjuYfikGcpvGPp/goqUbV9HYw==", + "subType": "06" + } + } + }, + "kmip_objectId_rand_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAHX65sNHnRYpx3VbWPCdQyFe7u0Y5ItabLEduqDeVsPk/iK4X3GjCSHQfw1yPi+CA+/veVpgdonwws6RiYV4ZZ5Q==", + "subType": "06" + } + } + }, + "kmip_objectId_det_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAHKU7mcdGEq2WGrDB6TicipLQstAk6G3PkiNt5F3bMavpKLjz04UBrd8aWGVG2gJTTON1UKRztiYFgRvb8f+LK/Q==", + "subType": "06" + } + } + }, + "kmip_objectId_det_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAHKU7mcdGEq2WGrDB6TicipLQstAk6G3PkiNt5F3bMavpKLjz04UBrd8aWGVG2gJTTON1UKRztiYFgRvb8f+LK/Q==", + "subType": "06" + } + } + }, + "kmip_objectId_det_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAHKU7mcdGEq2WGrDB6TicipLQstAk6G3PkiNt5F3bMavpKLjz04UBrd8aWGVG2gJTTON1UKRztiYFgRvb8f+LK/Q==", + "subType": "06" + } + } + }, + "kmip_bool_rand_auto_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAIw/xgJlKEvErmVtue3X3RFsOI2sttAbxnzh1INc9GUQ2vok1VwYt9k88RxMPiOwMAZG7P1MlAdx7zt865onPKOw==", + "subType": "06" + } + } + }, + "kmip_bool_rand_auto_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAIn8IuzlNHbpTgXOd1wEp364zJOBxj2Zf7a9B5osUV1sDY0G1OVpEnuDvZeUsdiUSyRjTTxzyuD/KZlKZ3+qrnrA==", + "subType": "06" + } + } + }, + "kmip_bool_rand_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAI3Nz9PdjUYQRGfTtvYSR8EQuUKFL0wdlEdfSCTBmMBhBPuuF9KxqCgy+ldVu1DRRgg3346DOKEEtE9BJPPInJ6Q==", + "subType": "06" + } + } + }, + "kmip_bool_rand_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAIEGjqoerIZBk8Rw+YTO7jFKWzagDS8mEpD+9Wm1Q0r0ZHUmV0dQZcIqRV4oUk8U8uHUn0N3t2qGLr+rhUs4GH/g==", + "subType": "06" + } + } + }, + "kmip_bool_det_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "kmip_bool_det_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "kmip_date_rand_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJgr0v4xetUXjlLcPcyKv/rzjtWOKp9CZJcm23Noglu5RR/rXJS0qKI+W9MmJ64TMf27KvaJ0UXwfTRrvOC1plCg==", + "subType": "06" + } + } + }, + "kmip_date_rand_auto_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJoeysAaiPsVK+JL1P1vD/9xF92m5kKidUdn6yklPlSKN4VVEBTymDetTLujULs1u1TlrS71jVLxo3xEwpG/KQvg==", + "subType": "06" + } + } + }, + "kmip_date_rand_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJVwu4+Su0DktpnZvzTBHYpWbWTq5gho/SLijrcIrFJcvq4YrjjPCXv+odCl95tkH+J1RlJdQ5Cr0umEIazLa6GA==", + "subType": "06" + } + } + }, + "kmip_date_rand_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAJWTYpjbDkIf82QXHMGrvd0SqhP8cBIakfYJf5aNcNrs86vxRhiG3KwETWPeOOlPZ6n1WjE2bOLB+DJTAxmJvahA==", + "subType": "06" + } + } + }, + "kmip_date_det_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAJ/+sQrUqQh+JADSVIKM0d68gDUhDy37M1z1uvROzQw6hUAbQeD0DWdztADKg560UTPM4uOgH4NAyhLyBLMrWWHg==", + "subType": "06" + } + } + }, + "kmip_date_det_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAJ/+sQrUqQh+JADSVIKM0d68gDUhDy37M1z1uvROzQw6hUAbQeD0DWdztADKg560UTPM4uOgH4NAyhLyBLMrWWHg==", + "subType": "06" + } + } + }, + "kmip_date_det_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAJ/+sQrUqQh+JADSVIKM0d68gDUhDy37M1z1uvROzQw6hUAbQeD0DWdztADKg560UTPM4uOgH4NAyhLyBLMrWWHg==", + "subType": "06" + } + } + }, + "kmip_null_rand_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_rand_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_regex_rand_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALi8avMfpxSlDsSTqdxO8O2B1M79gOElyUIdXySQo7mvgHlf4oHQ7r94lL9dnsA2t/jmUmBKoGypaUQUSQE+9x+A==", + "subType": "06" + } + } + }, + "kmip_regex_rand_auto_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALfHerZ/KolaBrb5qi3SpeNVW+i/nh5mkcdtQg5f1pHePr68KryHucM/XDAzbMqrPlag2/41STGYdJqzYO7Mbppg==", + "subType": "06" + } + } + }, + "kmip_regex_rand_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALOhKDVAN5cuDyB1EuRFWgKKt0wGJ63E5pPY8Tq2TXMNgCxUUc5O+TE+Ux4ls/uMyOBA3gPzND0CZKiru0i7ACUQ==", + "subType": "06" + } + } + }, + "kmip_regex_rand_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAALK3Hg8xX9gX+d3vKh7aosRP9CS2CIFeG9sapZv3OAPv1eWjY62Cp/G16kJ0BQt33RYD+DzD3gWupfUSyNZR0gng==", + "subType": "06" + } + } + }, + "kmip_regex_det_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAALaQXA8rItT7ELVxO8XtAWdHuiXFFPmnMhS5PMrUy/6mRtbq4fvU9dascW7ozonKOh8ad6+MIT7B/STv9dVBF4Kw==", + "subType": "06" + } + } + }, + "kmip_regex_det_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAALaQXA8rItT7ELVxO8XtAWdHuiXFFPmnMhS5PMrUy/6mRtbq4fvU9dascW7ozonKOh8ad6+MIT7B/STv9dVBF4Kw==", + "subType": "06" + } + } + }, + "kmip_regex_det_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAALaQXA8rItT7ELVxO8XtAWdHuiXFFPmnMhS5PMrUy/6mRtbq4fvU9dascW7ozonKOh8ad6+MIT7B/STv9dVBF4Kw==", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAMoGkfmmUWTI+0aW7jVyCJ5Dgru1SCXBUmJSRzDL0D57pNruQ+79tVVcI6Uz5j87DhZFxShHbPjj583vLOOBNM3WGzZCpqH3serhHTWvXK+NM=", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_auto_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAMwu1WaRhhv43xgxLNxuenbND9M6mxGtCs9o4J5+yfL95XNB9Daie3RcLlyngz0pncBie6IqjhTycXsxTLQ94Jdg6m5GD5cU541LYKvhbv5f4=", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAM+CIoCAisUwhhJtWQLolxQGQWafniwYyvaJQHmJC94Uwbf1gPfhMR42v2VtrmIVP0J0BaP/xf0cco2/qWRdKGZpgkK2CK6M972NtnZ/2x03A=", + "subType": "06" + } + } + }, + "kmip_dbPointer_rand_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAMjbeE9+EaJYjGfeAuxsV8teOdsW8bfnlkvji/tE11Zq89UMGx+oUsZzeLjUgVZ5nxsZKCZjEAq+DPnwFVC+MgqNeqWL7fRChODFlPGH2ZC+8=", + "subType": "06" + } + } + }, + "kmip_dbPointer_det_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAM5B+fjbjYCZzCYUu4N/pJI3srCCXN+OCCHweeweqmpIEmB7yw87bQRIMGtCm6HuekcZ5J5q+nY5AQb0du/wh1YIoOrC3u4w7ZcLHkDmuAJPg=", + "subType": "06" + } + } + }, + "kmip_dbPointer_det_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAM5B+fjbjYCZzCYUu4N/pJI3srCCXN+OCCHweeweqmpIEmB7yw87bQRIMGtCm6HuekcZ5J5q+nY5AQb0du/wh1YIoOrC3u4w7ZcLHkDmuAJPg=", + "subType": "06" + } + } + }, + "kmip_dbPointer_det_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAM5B+fjbjYCZzCYUu4N/pJI3srCCXN+OCCHweeweqmpIEmB7yw87bQRIMGtCm6HuekcZ5J5q+nY5AQb0du/wh1YIoOrC3u4w7ZcLHkDmuAJPg=", + "subType": "06" + } + } + }, + "kmip_javascript_rand_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANuzlkWs/c8xArrAxPgYuCeShjj1zCfIMHOTPohspcyNofo9iY3P5MlhEOprZDiS8dBFg6EB7fZDzDdczx6VCN2A==", + "subType": "06" + } + } + }, + "kmip_javascript_rand_auto_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANwJ72y7UqCBJh1NwVRiE3vU1ex7FMv/X5YWCMuO9MHPMo4g1V5eaO4KfOr+K8+9NtkflgMpeDkvwP92rfR5ud5Q==", + "subType": "06" + } + } + }, + "kmip_javascript_rand_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANj5q+888itRnLsw9PNGsBLhgqpvem5IJBOE2292r6zwjVueoEK/2I2PesRnn0esnkwdia1ADoMkcLUegwcFRkWQ==", + "subType": "06" + } + } + }, + "kmip_javascript_rand_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAANnvbnmApys7OIe8LGTsZKDG1F1G1SI/rfZVmF6q1fq5U7feYPp1ejb2t2S2+v7LfcOHytsQWGcYuWCDcl+vosvQ==", + "subType": "06" + } + } + }, + "kmip_javascript_det_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAANOR9R/Da8j5iVxllLiGFlv4U/bVn/PyN9/5WeGJkGJeE/j/osKrKx6IL1igI0YVI+pKKzsINqJGIv+bJX0s7MNw==", + "subType": "06" + } + } + }, + "kmip_javascript_det_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAANOR9R/Da8j5iVxllLiGFlv4U/bVn/PyN9/5WeGJkGJeE/j/osKrKx6IL1igI0YVI+pKKzsINqJGIv+bJX0s7MNw==", + "subType": "06" + } + } + }, + "kmip_javascript_det_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAANOR9R/Da8j5iVxllLiGFlv4U/bVn/PyN9/5WeGJkGJeE/j/osKrKx6IL1igI0YVI+pKKzsINqJGIv+bJX0s7MNw==", + "subType": "06" + } + } + }, + "kmip_symbol_rand_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOe+vXpJSkmBM3WkxZrn4ea9/C6iNyMXWUzkQIzIYlnbkyu8od8nfOdhobUhoFxcKnvdaxN1s5NhJ1FA97RN/upGYN+AI/7cTCElmFSpdSvkI=", + "subType": "06" + } + } + }, + "kmip_symbol_rand_auto_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOPpCgK6Hc/M2elOJkwIU9J7PZa+h1chody2yvfDu/UlB6T5sxnEZ6aEY/ISNLhJlhsRzuApSgFOmnrcG6Eg9VnSKin2yK0ll+VFxQEDHAcSA=", + "subType": "06" + } + } + }, + "kmip_symbol_rand_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOVoHX9GaOn71L5D9TpZmmxkx/asr0FHCLG5ZgLLA04yIhZHsDjt2DiVGGO/Mf4KwvoBn7Cf08qMhW7rQh2LgvvSLBO3zbw5l+MZ/bSn+Jylo=", + "subType": "06" + } + } + }, + "kmip_symbol_rand_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAOPobmcO/I4QObtCUEmGWpSCJ6tlYyhbO59q78LZBucSNl7DSkf/13tOJ9t+WKXACcMKVMmfPoFsgHbVj1nKWULBT07n1OWWDTZkuMD6C2+Fc=", + "subType": "06" + } + } + }, + "kmip_symbol_det_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAOPpwX4mafoQJYHuzYfbKW1JunpjpB7Nd2slTC3n8Hsas9wQYf9VkModQhe5M4wZHOIXpehaODRcjKKfKRmpnNBOURSLm/ORJvy+UxtSLsnqo=", + "subType": "06" + } + } + }, + "kmip_symbol_det_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAOPpwX4mafoQJYHuzYfbKW1JunpjpB7Nd2slTC3n8Hsas9wQYf9VkModQhe5M4wZHOIXpehaODRcjKKfKRmpnNBOURSLm/ORJvy+UxtSLsnqo=", + "subType": "06" + } + } + }, + "kmip_symbol_det_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAOPpwX4mafoQJYHuzYfbKW1JunpjpB7Nd2slTC3n8Hsas9wQYf9VkModQhe5M4wZHOIXpehaODRcjKKfKRmpnNBOURSLm/ORJvy+UxtSLsnqo=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_auto_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPW2VMMm+EvsYpVtJQhsxgxgvV35kr9nxqKxP2qqIOAOQ58R/1oyYScFkNwB/tw0A1/zdvhoo+ERa7c0tjLIojFrosXhX2N/8Z4VnbZruz0Nk=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_auto_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPjPq9BQR4EwG/CD+RthOJY04m99LCl/shY6HnaU/QL627kN1dbBAG5vs+MXfa+glg8waVTNgB94vm3j72FMV1ZOKvbl4faWF1Rl2EOpOlR9U=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPtqebrCAidKzBMvp3B5/vBeetqeCoMKS+vo+hLAYooXrnBunWxwRHpr45XYUvroG3aqOMkLtVZSgw8sO6Y/3z1viO2G0sGQW1ZMoW0/PX5Uw=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_rand_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAPtkJwXKlq8Fx1f1+9HFofM4uKi6lHQRFRyiOyUFJYxxZY1LR/2WXXTqWz3MWtrcJFCB+QSVOb1N/ieC7AZUboPgIuPJISM3Hu5VU2x/Isbdc=", + "subType": "06" + } + } + }, + "kmip_javascriptWithScope_det_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_det_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_int_rand_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQ50kE7Tby9od2OsmIGZhp9k/mj4vy/YdnmF6YsSPxihbjV1vXGMraI/nGCr+0H1riwzq3m4sCT7aPw2VgiuwKMA==", + "subType": "06" + } + } + }, + "kmip_int_rand_auto_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQkNL14OSMX/bJbsLtB/UumRoat6QOY7fvwZxRrkXTS3VJVHigthI1cUX7Is/uUsY8oHOfk/ZuHklQkifmfdcklQ==", + "subType": "06" + } + } + }, + "kmip_int_rand_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQtN2gNVU9Itoj+vgcK/4jEB5baSUH+Qz2WqTY7m0XaA3bPWGFCiWY4Sdw+qovednrSSSbC+azWi1QYclFRraldQ==", + "subType": "06" + } + } + }, + "kmip_int_rand_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAQk6uBqwXXFF9zEM4bc124goI3pBy2Jdi8Cd0ycKkjXrPG7GVCUm2UMbO+zEzYODeVo35N11g2yMXcv9RVgjWtNA==", + "subType": "06" + } + } + }, + "kmip_int_det_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAQgrkPEf+RBZMn/J7HZObqEfus8icYls6ecaUrlabI6v1ALgxLuv23WSIfTr6mqpQCounqdA14DWS/Wl3kSkVC0w==", + "subType": "06" + } + } + }, + "kmip_int_det_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAQgrkPEf+RBZMn/J7HZObqEfus8icYls6ecaUrlabI6v1ALgxLuv23WSIfTr6mqpQCounqdA14DWS/Wl3kSkVC0w==", + "subType": "06" + } + } + }, + "kmip_int_det_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAQgrkPEf+RBZMn/J7HZObqEfus8icYls6ecaUrlabI6v1ALgxLuv23WSIfTr6mqpQCounqdA14DWS/Wl3kSkVC0w==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAAR2Cu3o2e/u5o69MndeZPJU5ngVA1G2MNYn00t+up/GlmaUC1ni1CVl0ZR0EVZ0gCDUrfxwPISPib8y23tNjbsog==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_auto_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAARgi8stgSQwqnN4Ws2ZBILOREsjreZcS1MBerL7dbGLVfzW99tqECglhGokkrE0aY69L0xMgcAUIaFRN4GanQAPg==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAARPxEEI8L5Q3Jybu88BLdf31T3uYEUbijgSlKlkTt141RYrlE8nxtiYU5/5H9GXBis0Qq1s2C+MauD2h/cNijTCA==", + "subType": "06" + } + } + }, + "kmip_timestamp_rand_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAARh/QaU1dnGbii4LtXCpT5o6vencc8E2fzarjJFbSEd0ixW/UV1ppZdvD729d0umkaIwIEVA4q+XVvHfl/ckKPFg==", + "subType": "06" + } + } + }, + "kmip_timestamp_det_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAARqdpLb72mmzb75QBrE+ATMfS5LLqzAD/1g5ScT8zfgh0IHsZZBWCJlSVRNC12Sgr3zdXHMtYp8C3OZT6/tPkQGg==", + "subType": "06" + } + } + }, + "kmip_timestamp_det_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAARqdpLb72mmzb75QBrE+ATMfS5LLqzAD/1g5ScT8zfgh0IHsZZBWCJlSVRNC12Sgr3zdXHMtYp8C3OZT6/tPkQGg==", + "subType": "06" + } + } + }, + "kmip_timestamp_det_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAARqdpLb72mmzb75QBrE+ATMfS5LLqzAD/1g5ScT8zfgh0IHsZZBWCJlSVRNC12Sgr3zdXHMtYp8C3OZT6/tPkQGg==", + "subType": "06" + } + } + }, + "kmip_long_rand_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASVv+ClXkh9spIaXWJYRV/o8UZjG+WWWrNpIjZ9LQn2bXakrKJ3REvdkrzGuxASmBhBYTplEyvxVCJwXuWRAGGYw==", + "subType": "06" + } + } + }, + "kmip_long_rand_auto_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASeAz/dK+Gc4/jx3W07B2rNFvQ0LoyCllFRvRVGu1Xf1NByc4cRZLOMzlr99syz/fifF6WY30bOi5Pani9QtFuGg==", + "subType": "06" + } + } + }, + "kmip_long_rand_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASP1HD9uoDlwTldaznKxW71JUQcLsa4/cUWzeTnelQwdpohCbZsM8fBZBqgwwTWnjpYY/LBUipC6yhwLKfUXBoBQ==", + "subType": "06" + } + } + }, + "kmip_long_rand_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAASnGPH77bS/ETB1hn+VTvsBrxEvIHA6EAb8Z2SEz6BHt7SVeI+I7DLERvRVpV5kNJFcKgXDrvRmD+Et0rhSmk9sw==", + "subType": "06" + } + } + }, + "kmip_long_det_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAS+zKmtijSTPOEVlpwmaeMIOuzVNuZpV4Jw9zP8Yqa1xYtlItXDozqdibacRaA74KU49KNySdR1T7fxwxa2OOTrQ==", + "subType": "06" + } + } + }, + "kmip_long_det_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAS+zKmtijSTPOEVlpwmaeMIOuzVNuZpV4Jw9zP8Yqa1xYtlItXDozqdibacRaA74KU49KNySdR1T7fxwxa2OOTrQ==", + "subType": "06" + } + } + }, + "kmip_long_det_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "ASjCDwAAAAAAAAAAAAAAAAAS+zKmtijSTPOEVlpwmaeMIOuzVNuZpV4Jw9zP8Yqa1xYtlItXDozqdibacRaA74KU49KNySdR1T7fxwxa2OOTrQ==", + "subType": "06" + } + } + }, + "kmip_decimal_rand_auto_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATu/BbCc5Ti9SBlMR2B8zj3Q1yQ16Uob+10LWaT5QKS192IcnBGy4wmmNkIsTys060xUby9KKQF80dVPnjYfqJwEXCe/pVaPQZftE0DolKv78=", + "subType": "06" + } + } + }, + "kmip_decimal_rand_auto_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATpq6/dtxq2ZUZHrK10aB0YjjPalEaXYcyAyRZjfXWAYCLZdT9sIybjX3Axjxisim+VSHx0QU7oXkKUfcbLgHyjUXj8g9059FHxKFkUsNv4Z8=", + "subType": "06" + } + } + }, + "kmip_decimal_rand_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATS++9KcfM7uiShZYxRpFPrBJquKv7dyvFRTjnxs6aaaPo0fiqpv6bco/cMLsldEVpWDEA/Tc2HtSXYPp4UJsMfASyBjoxCloL5SaRWyD9Ye8=", + "subType": "06" + } + } + }, + "kmip_decimal_rand_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AijCDwAAAAAAAAAAAAAAAAATREcETS5KoAGyj/P45owPrdFfy5ng8Z1ND+F+780lLddOyPeDnIsa7yg6uvhTZ65mHfGLvKcFocclYenq/AX1dY4xdjLRg/AfT088A27ORUA=", + "subType": "06" + } + } + }, + "kmip_decimal_det_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_det_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_minKey_rand_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_rand_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_maxKey_rand_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_rand_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } } } \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-key-kmip.json b/tests/SpecTests/client-side-encryption/corpus/corpus-key-kmip.json new file mode 100644 index 000000000..7c7069700 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-key-kmip.json @@ -0,0 +1,32 @@ +{ + "_id": { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "eUYDyB0HuWb+lQgUwO+6qJQyTTDTY2gp9FbemL7ZFo0pvr0x6rm6Ff9OVUTGH6HyMKipaeHdiIJU1dzsLwvqKvi7Beh+U4iaIWX/K0oEg1GOsJc0+Z/in8gNHbGUYLmycHViM3LES3kdt7FdFSUl5rEBHrM71yoNEXImz17QJWMGOuT4x6yoi2pvnaRJwfrI4DjpmnnTrDMac92jgZehbg==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "kmip", + "keyId": "1" + }, + "keyAltNames": ["kmip"] +} \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json b/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json index f145f712a..e74bc914f 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus-schema.json @@ -5064,6 +5064,1272 @@ "bsonType": "binData" } } + }, + "kmip_double_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "kmip_double_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "double" + } + } + } + }, + "kmip_double_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_double_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "kmip_string_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "string" + } + } + } + }, + "kmip_string_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "string" + } + } + } + }, + "kmip_string_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_string_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_object_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "kmip_object_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "object" + } + } + } + }, + "kmip_object_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_object_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_array_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "kmip_array_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "array" + } + } + } + }, + "kmip_array_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_array_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=00_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=00_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=00_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=00_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=04_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=04_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "binData" + } + } + } + }, + "kmip_binData=04_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_binData=04_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "kmip_objectId_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "objectId" + } + } + } + }, + "kmip_objectId_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "objectId" + } + } + } + }, + "kmip_objectId_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_objectId_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_bool_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "kmip_bool_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "bool" + } + } + } + }, + "kmip_bool_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_bool_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "kmip_date_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "date" + } + } + } + }, + "kmip_date_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "date" + } + } + } + }, + "kmip_date_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_date_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "kmip_regex_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "regex" + } + } + } + }, + "kmip_regex_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "regex" + } + } + } + }, + "kmip_regex_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_regex_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "kmip_dbPointer_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "dbPointer" + } + } + } + }, + "kmip_dbPointer_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "dbPointer" + } + } + } + }, + "kmip_dbPointer_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_dbPointer_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "kmip_javascript_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascript" + } + } + } + }, + "kmip_javascript_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "javascript" + } + } + } + }, + "kmip_javascript_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascript_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "kmip_symbol_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "symbol" + } + } + } + }, + "kmip_symbol_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "symbol" + } + } + } + }, + "kmip_symbol_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_symbol_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascriptWithScope_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "kmip_javascriptWithScope_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "javascriptWithScope" + } + } + } + }, + "kmip_javascriptWithScope_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_javascriptWithScope_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "kmip_int_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "int" + } + } + } + }, + "kmip_int_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "int" + } + } + } + }, + "kmip_int_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_int_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "kmip_timestamp_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "timestamp" + } + } + } + }, + "kmip_timestamp_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "timestamp" + } + } + } + }, + "kmip_timestamp_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_timestamp_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "kmip_long_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "long" + } + } + } + }, + "kmip_long_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_det_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic", + "bsonType": "long" + } + } + } + }, + "kmip_long_det_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_long_det_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_decimal_rand_auto_id": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "KMIPAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "kmip_decimal_rand_auto_altname": { + "bsonType": "object", + "properties": { + "value": { + "encrypt": { + "keyId": "/altname_kmip", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random", + "bsonType": "decimal" + } + } + } + }, + "kmip_decimal_rand_explicit_id": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } + }, + "kmip_decimal_rand_explicit_altname": { + "bsonType": "object", + "properties": { + "value": { + "bsonType": "binData" + } + } } } } \ No newline at end of file diff --git a/tests/SpecTests/client-side-encryption/corpus/corpus.json b/tests/SpecTests/client-side-encryption/corpus/corpus.json index 55bbaf99c..559711b34 100644 --- a/tests/SpecTests/client-side-encryption/corpus/corpus.json +++ b/tests/SpecTests/client-side-encryption/corpus/corpus.json @@ -4,6 +4,7 @@ "altname_local": "local", "altname_azure": "azure", "altname_gcp": "gcp", + "altname_kmip": "kmip", "aws_double_rand_auto_id": { "kms": "aws", "type": "double", @@ -6648,6 +6649,1667 @@ "$maxKey": 1 } }, + "kmip_double_rand_auto_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_rand_auto_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_rand_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_rand_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_det_explicit_id": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_double_det_explicit_altname": { + "kms": "kmip", + "type": "double", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDouble": "1.234" + } + }, + "kmip_string_rand_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_rand_auto_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_rand_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_rand_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_det_auto_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_det_explicit_id": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": "mongodb" + }, + "kmip_string_det_explicit_altname": { + "kms": "kmip", + "type": "string", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": "mongodb" + }, + "kmip_object_rand_auto_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_rand_auto_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_rand_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_rand_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_det_explicit_id": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_object_det_explicit_altname": { + "kms": "kmip", + "type": "object", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "x": { + "$numberInt": "1" + } + } + }, + "kmip_array_rand_auto_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_rand_auto_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_rand_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_rand_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_det_explicit_id": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_array_det_explicit_altname": { + "kms": "kmip", + "type": "array", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": [ + { + "$numberInt": "1" + }, + { + "$numberInt": "2" + }, + { + "$numberInt": "3" + } + ] + }, + "kmip_binData=00_rand_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_rand_auto_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_rand_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_det_auto_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_det_explicit_id": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=00_det_explicit_altname": { + "kms": "kmip", + "type": "binData=00", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AQIDBA==", + "subType": "00" + } + } + }, + "kmip_binData=04_rand_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_rand_auto_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_rand_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_rand_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_det_auto_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_det_explicit_id": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_binData=04_det_explicit_altname": { + "kms": "kmip", + "type": "binData=04", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$binary": { + "base64": "AAECAwQFBgcICQoLDA0ODw==", + "subType": "04" + } + } + }, + "kmip_undefined_rand_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_rand_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_id": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_undefined_det_explicit_altname": { + "kms": "kmip", + "type": "undefined", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$undefined": true + } + }, + "kmip_objectId_rand_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_rand_auto_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_rand_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_rand_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_det_auto_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_det_explicit_id": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_objectId_det_explicit_altname": { + "kms": "kmip", + "type": "objectId", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$oid": "01234567890abcdef0123456" + } + }, + "kmip_bool_rand_auto_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": true + }, + "kmip_bool_rand_auto_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": true + }, + "kmip_bool_rand_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": true + }, + "kmip_bool_rand_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": true + }, + "kmip_bool_det_explicit_id": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": true + }, + "kmip_bool_det_explicit_altname": { + "kms": "kmip", + "type": "bool", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": true + }, + "kmip_date_rand_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_rand_auto_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_rand_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_rand_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_det_auto_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_det_explicit_id": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_date_det_explicit_altname": { + "kms": "kmip", + "type": "date", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$date": { + "$numberLong": "12345" + } + } + }, + "kmip_null_rand_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_rand_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_id": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": null + }, + "kmip_null_det_explicit_altname": { + "kms": "kmip", + "type": "null", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": null + }, + "kmip_regex_rand_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_rand_auto_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_rand_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_rand_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_det_auto_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_det_explicit_id": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_regex_det_explicit_altname": { + "kms": "kmip", + "type": "regex", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$regularExpression": { + "pattern": ".*", + "options": "" + } + } + }, + "kmip_dbPointer_rand_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_rand_auto_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_rand_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_rand_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_det_auto_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_det_explicit_id": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_dbPointer_det_explicit_altname": { + "kms": "kmip", + "type": "dbPointer", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$dbPointer": { + "$ref": "db.example", + "$id": { + "$oid": "01234567890abcdef0123456" + } + } + } + }, + "kmip_javascript_rand_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_rand_auto_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_rand_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_rand_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_det_auto_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_det_explicit_id": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_javascript_det_explicit_altname": { + "kms": "kmip", + "type": "javascript", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1" + } + }, + "kmip_symbol_rand_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_rand_auto_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_rand_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_rand_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_det_auto_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_det_explicit_id": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_symbol_det_explicit_altname": { + "kms": "kmip", + "type": "symbol", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$symbol": "mongodb-symbol" + } + }, + "kmip_javascriptWithScope_rand_auto_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_rand_auto_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_rand_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_rand_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_det_explicit_id": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_javascriptWithScope_det_explicit_altname": { + "kms": "kmip", + "type": "javascriptWithScope", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$code": "x=1", + "$scope": {} + } + }, + "kmip_int_rand_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_rand_auto_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_rand_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_rand_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_det_auto_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_det_explicit_id": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_int_det_explicit_altname": { + "kms": "kmip", + "type": "int", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberInt": "123" + } + }, + "kmip_timestamp_rand_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_rand_auto_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_rand_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_rand_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_det_auto_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_det_explicit_id": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_timestamp_det_explicit_altname": { + "kms": "kmip", + "type": "timestamp", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$timestamp": { + "t": 0, + "i": 12345 + } + } + }, + "kmip_long_rand_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_rand_auto_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_rand_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_rand_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_det_auto_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_det_explicit_id": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_long_det_explicit_altname": { + "kms": "kmip", + "type": "long", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberLong": "456" + } + }, + "kmip_decimal_rand_auto_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_rand_auto_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "auto", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_rand_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_rand_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": true, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_det_explicit_id": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_decimal_det_explicit_altname": { + "kms": "kmip", + "type": "decimal", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$numberDecimal": "1.234" + } + }, + "kmip_minKey_rand_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_rand_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_id": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_minKey_det_explicit_altname": { + "kms": "kmip", + "type": "minKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$minKey": 1 + } + }, + "kmip_maxKey_rand_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_rand_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "rand", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_id": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "id", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, + "kmip_maxKey_det_explicit_altname": { + "kms": "kmip", + "type": "maxKey", + "algo": "det", + "method": "explicit", + "identifier": "altname", + "allowed": false, + "value": { + "$maxKey": 1 + } + }, "payload=0,algo=rand": { "kms": "local", "type": "string", diff --git a/tests/SpecTests/client-side-encryption/tests/azureKMS.json b/tests/SpecTests/client-side-encryption/tests/azureKMS.json index f0f5329d7..afecf40b0 100644 --- a/tests/SpecTests/client-side-encryption/tests/azureKMS.json +++ b/tests/SpecTests/client-side-encryption/tests/azureKMS.json @@ -64,6 +64,20 @@ "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } + }, + "encrypted_string_kmip": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } } }, "bsonType": "object" diff --git a/tests/SpecTests/client-side-encryption/tests/gcpKMS.json b/tests/SpecTests/client-side-encryption/tests/gcpKMS.json index 297d5d0dc..c2c08b8a2 100644 --- a/tests/SpecTests/client-side-encryption/tests/gcpKMS.json +++ b/tests/SpecTests/client-side-encryption/tests/gcpKMS.json @@ -64,6 +64,20 @@ "bsonType": "string", "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" } + }, + "encrypted_string_kmip": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } } }, "bsonType": "object" diff --git a/tests/SpecTests/client-side-encryption/tests/kmipKMS.json b/tests/SpecTests/client-side-encryption/tests/kmipKMS.json new file mode 100644 index 000000000..5749d21ab --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/kmipKMS.json @@ -0,0 +1,223 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": { + "encrypted_string_aws": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_azure": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AZURE+AAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_gcp": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "GCP+AAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_local": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "encrypted_string_kmip": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "eUYDyB0HuWb+lQgUwO+6qJQyTTDTY2gp9FbemL7ZFo0pvr0x6rm6Ff9OVUTGH6HyMKipaeHdiIJU1dzsLwvqKvi7Beh+U4iaIWX/K0oEg1GOsJc0+Z/in8gNHbGUYLmycHViM3LES3kdt7FdFSUl5rEBHrM71yoNEXImz17QJWMGOuT4x6yoi2pvnaRJwfrI4DjpmnnTrDMac92jgZehbg==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1634220190041" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "kmip", + "keyId": "1" + }, + "keyAltNames": [ + "altname", + "kmip_altname" + ] + } + ], + "tests": [ + { + "description": "Insert a document with auto encryption using KMIP KMS provider", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "kmip": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string_kmip": "string0" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "dBHpr8aITfeBQ15grpbLpQ==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault" + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encrypted_string_kmip": { + "$binary": { + "base64": "AXQR6a/GiE33gUNeYK6Wy6UCKCwtKFIsL8eKObDVxvqGupJNUk7kXswHhB7G5j/C1D+6no+Asra0KgSU43bTL3ooIBLVyIzbV5CDJYqzAsa4WQ==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string_kmip": { + "$binary": { + "base64": "AXQR6a/GiE33gUNeYK6Wy6UCKCwtKFIsL8eKObDVxvqGupJNUk7kXswHhB7G5j/C1D+6no+Asra0KgSU43bTL3ooIBLVyIzbV5CDJYqzAsa4WQ==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} From e4aa59ab15b6fe00a0e56b6772f8b515a0f01bf0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 14 Dec 2021 18:38:18 -0500 Subject: [PATCH 103/321] Update CI configs for ext-mongodb 1.12.0 (#882) * Update extension version in CI configs for 1.12.0 release * Bump extension requirement to 1.12.0 * Update shivammathur/setup-php requirements for v2 --- .evergreen/config.yml | 35 ++++++-------------------- .github/workflows/coding-standards.yml | 5 ++-- .github/workflows/tests.yml | 11 ++++---- composer.json | 2 +- 4 files changed, 16 insertions(+), 37 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 12435875a..c2258f6c2 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -609,21 +609,16 @@ axes: - id: driver-versions display_name: Driver Version values: - # TODO: Update references to master branch after PHPC 1.12 is released - - id: "lowest-supported" - # display_name: "1.11.0" - display_name: "1.12-dev" + - id: "oldest-supported" + display_name: "1.12.0" variables: - EXTENSION_BRANCH: "master" + EXTENSION_VERSION: "1.12.0" - id: "latest-stable" - # display_name: "Latest Stable (1.11.x)" - display_name: "1.12-dev" + display_name: "1.12.x" variables: - # EXTENSION_VERSION: "stable" - EXTENSION_BRANCH: "master" + EXTENSION_VERSION: "stable" - id: "latest-dev" - # display_name: "1.12-dev (master)" - display_name: "1.12-dev" + display_name: "1.13-dev (master)" variables: EXTENSION_BRANCH: "master" @@ -728,20 +723,6 @@ buildvariants: - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests all driver versions on all PHP versions using latest MongoDB and Ubuntu 18.04 -- matrix_name: "test-driver-versions" - matrix_spec: { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "*" } - exclude_spec: - # Avoid duplicate build variants from test-php-versions - - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "lowest-supported" } - - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-stable" } - - { "os": "ubuntu1804-arm64-test", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-dev" } - display_name: "${os}, MongoDB ${edge-versions}, PHP ${php-versions}, ext-mongodb ${driver-versions}" - tasks: - - name: "test-standalone" - - name: "test-replica_set" - - name: "test-sharded_cluster" - # Tests all MongoDB versions with latest stable PHP and driver versions - matrix_name: "test-mongodb-versions" matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } @@ -754,10 +735,10 @@ buildvariants: - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests all MongoDB versions with lowest supported PHP and driver versions +# Tests all MongoDB versions with oldest supported PHP and driver versions # Enables --prefer-lowest for composer to test oldest dependencies against all server versions - matrix_name: "test-dependencies" - matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "oldest-supported", "driver-versions": "lowest-supported", "dependencies": "lowest" } + matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "oldest-supported", "driver-versions": "oldest-supported", "dependencies": "lowest" } display_name: "Lowest Dependencies: ${os}, MongoDB ${versions}, PHP ${php-edge-versions}, ext-mongodb ${driver-versions}" tasks: - name: "test-standalone" diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index b9f2fc134..0a584a558 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -20,7 +20,7 @@ jobs: php-version: - "7.4" driver-version: - - "mongodb/mongo-php-driver@master" + - "stable" steps: - name: "Checkout" @@ -42,8 +42,7 @@ jobs: restore-keys: ${{ steps.extcache.outputs.key }} - name: "Install PHP" - # Todo: switch to @v2 once a tag has been created - uses: "shivammathur/setup-php@develop" + uses: "shivammathur/setup-php@v2" with: coverage: "none" extensions: "mongodb-${{ matrix.driver-version }}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e317da929..9a9f32c4f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,24 +27,24 @@ jobs: mongodb-version: - "4.4" driver-version: - - "mongodb/mongo-php-driver@master" + - "stable" topology: - "server" include: - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "5.0" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "server" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "replica_set" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "sharded_cluster" steps: @@ -75,8 +75,7 @@ jobs: restore-keys: ${{ steps.extcache.outputs.key }} - name: "Install PHP" - # Todo: switch to @v2 once a tag has been created - uses: "shivammathur/setup-php@develop" + uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" tools: "pecl" diff --git a/composer.json b/composer.json index a0b0ca6e3..915b429c2 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.2 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.11.0", + "ext-mongodb": "^1.12.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, From e346802c14375e3937db5249585f3a1ff173e860 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 14 Dec 2021 19:16:03 -0500 Subject: [PATCH 104/321] Master is now 1.12-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 915b429c2..1e70ade99 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.11.x-dev" + "dev-master": "1.12.x-dev" } } } From 6627ea1ac1835609c88dba2f297580d04765d3ae Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 30 Dec 2021 10:43:07 -0500 Subject: [PATCH 105/321] PHPLIB-775: Revert to stable versions in GitHub CI (#883) --- .github/workflows/coding-standards.yml | 5 ++--- .github/workflows/tests.yml | 11 +++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index b9f2fc134..0a584a558 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -20,7 +20,7 @@ jobs: php-version: - "7.4" driver-version: - - "mongodb/mongo-php-driver@master" + - "stable" steps: - name: "Checkout" @@ -42,8 +42,7 @@ jobs: restore-keys: ${{ steps.extcache.outputs.key }} - name: "Install PHP" - # Todo: switch to @v2 once a tag has been created - uses: "shivammathur/setup-php@develop" + uses: "shivammathur/setup-php@v2" with: coverage: "none" extensions: "mongodb-${{ matrix.driver-version }}" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dbde407ee..e0b88fe70 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,24 +26,24 @@ jobs: mongodb-version: - "4.4" driver-version: - - "mongodb/mongo-php-driver@master" + - "stable" topology: - "server" include: - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "5.0" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "server" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "replica_set" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "sharded_cluster" steps: @@ -74,8 +74,7 @@ jobs: restore-keys: ${{ steps.extcache.outputs.key }} - name: "Install PHP" - # Todo: switch to @v2 once a tag has been created - uses: "shivammathur/setup-php@develop" + uses: "shivammathur/setup-php@v2" with: php-version: "${{ matrix.php-version }}" tools: "pecl" From c41a46fc2c57e8689fe6edfa086f60024061d977 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 30 Dec 2021 13:08:29 -0500 Subject: [PATCH 106/321] PHPLIB-740: Support authorizedCollections option for listCollections (#884) * PHPLIB-740: Support authorizedCollections option for listCollections * Update tests and docs for authorizedDatabases option --- ...oDBClient-method-listDatabases-option.yaml | 2 +- ...atabase-method-listCollections-option.yaml | 15 +++++++++++++++ src/Command/ListCollections.php | 19 +++++++++++++------ src/Command/ListDatabases.php | 14 ++++---------- src/Operation/ListCollectionNames.php | 5 +++++ src/Operation/ListCollections.php | 5 +++++ tests/Command/ListCollectionsTest.php | 4 ++++ .../ListCollectionNamesFunctionalTest.php | 18 ++++++++++++++++++ .../ListCollectionsFunctionalTest.php | 18 ++++++++++++++++++ .../ListDatabaseNamesFunctionalTest.php | 2 +- .../Operation/ListDatabasesFunctionalTest.php | 1 + 11 files changed, 85 insertions(+), 18 deletions(-) diff --git a/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml b/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml index 4e3d616d8..b9a9c23e2 100644 --- a/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml @@ -4,7 +4,7 @@ type: boolean description: | A flag that determines which databases are returned based on the user privileges when access control is enabled. For more information, see the - `listDatabases command documentation `_. + `listDatabases command documentation `_. For servers < 4.0.5, this option is ignored. diff --git a/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml index 0d9ab968d..de05bf339 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml @@ -1,4 +1,19 @@ arg_name: option +name: authorizedCollections +type: boolean +description: | + A flag that determines which collections are returned based on the user + privileges when access control is enabled. For more information, see the + `listCollections command documentation `_. + + For servers < 4.0, this option is ignored. + + .. versionadded:: 1.12 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: filter type: array|object description: | diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index 4302e4f09..e3a28d374 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -49,6 +49,11 @@ class ListCollections implements Executable * * Supported options: * + * * authorizedCollections (boolean): Determines which collections are + * returned based on the user privileges. + * + * For servers < 4.0, this option is ignored. + * * * filter (document): Query by which to filter collections. * * * maxTimeMS (integer): The maximum amount of time to allow the query to @@ -68,6 +73,10 @@ class ListCollections implements Executable */ public function __construct($databaseName, array $options = []) { + if (isset($options['authorizedCollections']) && ! is_bool($options['authorizedCollections'])) { + throw InvalidArgumentException::invalidType('"authorizedCollections" option', $options['authorizedCollections'], 'boolean'); + } + if (isset($options['filter']) && ! is_array($options['filter']) && ! is_object($options['filter'])) { throw InvalidArgumentException::invalidType('"filter" option', $options['filter'], 'array or object'); } @@ -104,12 +113,10 @@ public function execute(Server $server) $cmd['filter'] = (object) $this->options['filter']; } - if (isset($this->options['maxTimeMS'])) { - $cmd['maxTimeMS'] = $this->options['maxTimeMS']; - } - - if (isset($this->options['nameOnly'])) { - $cmd['nameOnly'] = $this->options['nameOnly']; + foreach (['authorizedCollections', 'maxTimeMS', 'nameOnly'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } $cursor = $server->executeReadCommand($this->databaseName, new Command($cmd), $this->createOptions()); diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index 0a18d4961..cebddf781 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -108,20 +108,14 @@ public function execute(Server $server) { $cmd = ['listDatabases' => 1]; - if (isset($this->options['authorizedDatabases'])) { - $cmd['authorizedDatabases'] = $this->options['authorizedDatabases']; - } - if (! empty($this->options['filter'])) { $cmd['filter'] = (object) $this->options['filter']; } - if (isset($this->options['maxTimeMS'])) { - $cmd['maxTimeMS'] = $this->options['maxTimeMS']; - } - - if (isset($this->options['nameOnly'])) { - $cmd['nameOnly'] = $this->options['nameOnly']; + foreach (['authorizedDatabases', 'maxTimeMS', 'nameOnly'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } $cursor = $server->executeReadCommand('admin', new Command($cmd), $this->createOptions()); diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index 4c7c03b34..e21af9e3d 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -41,6 +41,11 @@ class ListCollectionNames implements Executable * * Supported options: * + * * authorizedCollections (boolean): Determines which collections are + * returned based on the user privileges. + * + * For servers < 4.0, this option is ignored. + * * * filter (document): Query by which to filter collections. * * * maxTimeMS (integer): The maximum amount of time to allow the query to diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php index 45cba5463..898091c98 100644 --- a/src/Operation/ListCollections.php +++ b/src/Operation/ListCollections.php @@ -44,6 +44,11 @@ class ListCollections implements Executable * * Supported options: * + * * authorizedCollections (boolean): Determines which collections are + * returned based on the user privileges. + * + * For servers < 4.0, this option is ignored. + * * * filter (document): Query by which to filter collections. * * * maxTimeMS (integer): The maximum amount of time to allow the query to diff --git a/tests/Command/ListCollectionsTest.php b/tests/Command/ListCollectionsTest.php index 85cabab3b..8ea941a75 100644 --- a/tests/Command/ListCollectionsTest.php +++ b/tests/Command/ListCollectionsTest.php @@ -21,6 +21,10 @@ public function provideInvalidConstructorOptions() { $options = []; + foreach ($this->getInvalidBooleanValues() as $value) { + $options[][] = ['authorizedCollections' => $value]; + } + foreach ($this->getInvalidDocumentValues() as $value) { $options[][] = ['filter' => $value]; } diff --git a/tests/Operation/ListCollectionNamesFunctionalTest.php b/tests/Operation/ListCollectionNamesFunctionalTest.php index 8f222fa5a..15f121c64 100644 --- a/tests/Operation/ListCollectionNamesFunctionalTest.php +++ b/tests/Operation/ListCollectionNamesFunctionalTest.php @@ -31,6 +31,24 @@ public function testListCollectionNamesForNewlyCreatedDatabase(): void } } + public function testAuthorizedCollectionsOption(): void + { + (new CommandObserver())->observe( + function (): void { + $operation = new ListCollectionNames( + $this->getDatabaseName(), + ['authorizedCollections' => true] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function (array $event): void { + $this->assertObjectHasAttribute('authorizedCollections', $event['started']->getCommand()); + $this->assertSame(true, $event['started']->getCommand()->authorizedCollections); + } + ); + } + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { diff --git a/tests/Operation/ListCollectionsFunctionalTest.php b/tests/Operation/ListCollectionsFunctionalTest.php index 4b1fdb7e6..abe184b25 100644 --- a/tests/Operation/ListCollectionsFunctionalTest.php +++ b/tests/Operation/ListCollectionsFunctionalTest.php @@ -80,6 +80,24 @@ public function testListCollectionsForNonexistentDatabase(): void $this->assertCount(0, $collections); } + public function testAuthorizedCollectionsOption(): void + { + (new CommandObserver())->observe( + function (): void { + $operation = new ListCollections( + $this->getDatabaseName(), + ['authorizedCollections' => true] + ); + + $operation->execute($this->getPrimaryServer()); + }, + function (array $event): void { + $this->assertObjectHasAttribute('authorizedCollections', $event['started']->getCommand()); + $this->assertSame(true, $event['started']->getCommand()->authorizedCollections); + } + ); + } + public function testSessionOption(): void { if (version_compare($this->getServerVersion(), '3.6.0', '<')) { diff --git a/tests/Operation/ListDatabaseNamesFunctionalTest.php b/tests/Operation/ListDatabaseNamesFunctionalTest.php index 8536fcbea..81d2e83f0 100644 --- a/tests/Operation/ListDatabaseNamesFunctionalTest.php +++ b/tests/Operation/ListDatabaseNamesFunctionalTest.php @@ -48,7 +48,7 @@ function (): void { }, function (array $event): void { $this->assertObjectHasAttribute('authorizedDatabases', $event['started']->getCommand()); - $this->assertSame(true, $event['started']->getCommand()->nameOnly); + $this->assertSame(true, $event['started']->getCommand()->authorizedDatabases); } ); } diff --git a/tests/Operation/ListDatabasesFunctionalTest.php b/tests/Operation/ListDatabasesFunctionalTest.php index 1346a5387..a14d913a1 100644 --- a/tests/Operation/ListDatabasesFunctionalTest.php +++ b/tests/Operation/ListDatabasesFunctionalTest.php @@ -51,6 +51,7 @@ function (): void { }, function (array $event): void { $this->assertObjectHasAttribute('authorizedDatabases', $event['started']->getCommand()); + $this->assertSame(true, $event['started']->getCommand()->authorizedDatabases); } ); } From c631acd49b322451180db420f87ea63ac84c5f7a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 14 Jan 2022 10:49:08 -0500 Subject: [PATCH 107/321] PHPLIB-697: Deprecate Collection::mapReduce() --- docs/reference/method/MongoDBCollection-mapReduce.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/reference/method/MongoDBCollection-mapReduce.txt b/docs/reference/method/MongoDBCollection-mapReduce.txt index 2796e3857..1da9c4bd3 100644 --- a/docs/reference/method/MongoDBCollection-mapReduce.txt +++ b/docs/reference/method/MongoDBCollection-mapReduce.txt @@ -2,6 +2,8 @@ MongoDB\\Collection::mapReduce() ================================= +.. deprecated:: 1.12 + .. versionadded:: 1.2 .. default-domain:: mongodb From 93ccf2969238cb0410bcb787f425687a6a6d0859 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 24 Jan 2022 17:28:11 -0500 Subject: [PATCH 108/321] PHPLIB-699: Versioned API strict migration doc examples (#886) --- tests/DocumentationExamplesTest.php | 60 +++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 2c8c54996..28d914b90 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1605,6 +1605,66 @@ public function testVersionedApi(): void // phpcs:enable } + public function testVersionedApiMigration(): void + { + if (version_compare($this->getServerVersion(), '5.0.0', '<')) { + $this->markTestSkipped('Versioned API is not supported'); + } + + $uriString = static::getUri(true); + + // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly + $serverApi = new \MongoDB\Driver\ServerApi('1', true); + $client = new \MongoDB\Client($uriString, [], ['serverApi' => $serverApi]); + $db = $client->selectDatabase($this->getDatabaseName()); + $db->dropCollection('sales'); + + // Start Versioned API Example 5 + $strtoutc = function (string $datetime) { + return new \MongoDB\BSON\UTCDateTime(new \DateTime($datetime)); + }; + + $db->sales->insertMany([ + ['_id' => 1, 'item' => 'abc', 'price' => 10, 'quantity' => 2, 'date' => $strtoutc('2021-01-01T08:00:00Z')], + ['_id' => 2, 'item' => 'jkl', 'price' => 20, 'quantity' => 1, 'date' => $strtoutc('2021-02-03T09:00:00Z')], + ['_id' => 3, 'item' => 'xyz', 'price' => 5, 'quantity' => 5, 'date' => $strtoutc('2021-02-03T09:05:00Z')], + ['_id' => 4, 'item' => 'abc', 'price' => 10, 'quantity' => 10, 'date' => $strtoutc('2021-02-15T08:00:00Z')], + ['_id' => 5, 'item' => 'xyz', 'price' => 5, 'quantity' => 10, 'date' => $strtoutc('2021-02-15T09:05:00Z')], + ['_id' => 6, 'item' => 'xyz', 'price' => 5, 'quantity' => 5, 'date' => $strtoutc('2021-02-15T12:05:10Z')], + ['_id' => 7, 'item' => 'xyz', 'price' => 5, 'quantity' => 10, 'date' => $strtoutc('2021-02-15T14:12:12Z')], + ['_id' => 8, 'item' => 'abc', 'price' => 10, 'quantity' => 5, 'date' => $strtoutc('2021-03-16T20:20:13Z')], + ]); + // End Versioned API Example 5 + + ob_start(); + + // Start Versioned API Example 6 + try { + $count = $db->sales->count(); + } catch (\MongoDB\Driver\Exception\CommandException $e) { + echo json_encode($e->getResultDocument()); + // { "ok": 0, "errmsg": "Provided apiStrict:true, but the command count is not in API Version 1", "code": 323, "codeName": "APIStrictError" } + } + + // End Versioned API Example 6 + + ob_end_clean(); + + $this->assertStringContainsString('Provided apiStrict:true, but the command count is not in API Version 1', $e->getMessage()); + $this->assertEquals(323 /* APIStrictError */, $e->getCode()); + + // Start Versioned API Example 7 + $count = $db->sales->countDocuments(); + // End Versioned API Example 7 + + $this->assertSame($count, $db->sales->countDocuments()); + + // Start Versioned API Example 8 + // 8 + // End Versioned API Example 8 + // phpcs:enable + } + /** * @doesNotPerformAssertions */ From f54147cbed717b711b1379691d67b58b70b0146d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 8 Feb 2022 13:45:26 -0500 Subject: [PATCH 109/321] PHPLIB-783, PHPLIB-784: Update load balancer testing config and CSFLE tests (#887) * PHPLIB-783: Update load balancer testing config Upstream changes in drivers-evergreen-tools now require passing LOAD_BALANCER to run-orchestration.sh. Additionally, service ID mocking is no longer required as of server version 5.1. Load balancer testing requires PHPC 1.13.x for CDRIVER-4207 * Remove PHP memory limit for Evergreen * PHPLIB-784: Replace example.com in CSFLE prose tests * Skip collMod test on sharded clusters due to inconsistent result reporting --- .evergreen/config.yml | 9 ++++---- phpunit.evergreen.xml | 1 + .../ModifyCollectionFunctionalTest.php | 22 +++++-------------- .../ClientSideEncryptionSpecTest.php | 14 ++++++------ 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index c2258f6c2..1aea04577 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -175,7 +175,7 @@ functions: params: script: | ${PREPARE_SHELL} - MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh + MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} LOAD_BALANCER=${LOAD_BALANCER} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh # run-orchestration generates expansion file with the MONGODB_URI for the cluster - command: expansions.update params: @@ -505,13 +505,12 @@ tasks: - func: "bootstrap mongo-orchestration" vars: TOPOLOGY: "sharded_cluster" + LOAD_BALANCER: "true" SSL: "yes" - func: "start load balancer" - func: "start kms servers" - func: "run tests" vars: - # Testing with HAProxy requires service ID mocking - MOCK_SERVICE_ID: 1 # Note: loadBalanced=true should already be appended to SINGLE_MONGOS_LB_URI MONGODB_URI: "${SINGLE_MONGOS_LB_URI}" SSL: "yes" @@ -767,7 +766,9 @@ buildvariants: - .serverless - matrix_name: "test-loadBalanced" - matrix_spec: { "versions": ["5.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + # TODO: Add "5.2" server version alongside "latest" following its GA release + # TODO: Revert driver-version to latest-stable after PHPC 1.13.0 is released (for CDRIVER-4207) + matrix_spec: { "versions": "latest", "php-edge-versions": "latest-stable", "driver-versions": "latest-dev" } display_name: "Load balanced - ${versions}" run_on: debian92-test tasks: diff --git a/phpunit.evergreen.xml b/phpunit.evergreen.xml index f9832761a..b157e92c4 100644 --- a/phpunit.evergreen.xml +++ b/phpunit.evergreen.xml @@ -12,6 +12,7 @@ + diff --git a/tests/Operation/ModifyCollectionFunctionalTest.php b/tests/Operation/ModifyCollectionFunctionalTest.php index 75f77649a..567bcdef7 100644 --- a/tests/Operation/ModifyCollectionFunctionalTest.php +++ b/tests/Operation/ModifyCollectionFunctionalTest.php @@ -5,8 +5,6 @@ use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\ModifyCollection; -use function array_key_exists; - class ModifyCollectionFunctionalTest extends FunctionalTestCase { /** @@ -16,6 +14,10 @@ class ModifyCollectionFunctionalTest extends FunctionalTestCase */ public function testCollMod(): void { + if ($this->isShardedCluster()) { + $this->markTestSkipped('Sharded clusters may report result inconsistently'); + } + $this->createCollection(); $indexes = [['key' => ['lastAccess' => 1], 'expireAfterSeconds' => 3]]; @@ -30,19 +32,7 @@ public function testCollMod(): void ); $result = $modifyCollection->execute($this->getPrimaryServer()); - if (array_key_exists('raw', $result)) { - /* Sharded environment, where we only assert if a shard had a successful update. For - * non-primary shards that don't have chunks for the collection, the result contains a - * "ns does not exist" error. */ - foreach ($result['raw'] as $shard) { - if (array_key_exists('ok', $shard) && $shard['ok'] == 1) { - $this->assertSame(3, $shard['expireAfterSeconds_old']); - $this->assertSame(1000, $shard['expireAfterSeconds_new']); - } - } - } else { - $this->assertSame(3, $result['expireAfterSeconds_old']); - $this->assertSame(1000, $result['expireAfterSeconds_new']); - } + $this->assertSame(3, $result['expireAfterSeconds_old']); + $this->assertSame(1000, $result['expireAfterSeconds_new']); } } diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 79c82b80d..9c34d61bf 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -665,8 +665,8 @@ public function testCustomEndpoint(Closure $test): void $clientEncryptionInvalid = $client->createClientEncryption([ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ - 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => 'example.com:443'], - 'gcp' => Context::getGCPCredentials() + ['endpoint' => 'example.com:443'], + 'azure' => Context::getAzureCredentials() + ['identityPlatformEndpoint' => 'doesnotexist.invalid:443'], + 'gcp' => Context::getGCPCredentials() + ['endpoint' => 'doesnotexist.invalid:443'], 'kmip' => ['endpoint' => 'doesnotexist.local:5698'], ], 'tlsOptions' => [ @@ -732,8 +732,8 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio yield 'Test 6' => [ static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $test->expectException(RuntimeException::class); - $test->expectExceptionMessageMatches('#parse error#'); - $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'example.com']]); + $test->expectExceptionMessageMatches('#doesnotexist.invalid#'); + $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'doesnotexist.invalid']]); }, ]; @@ -744,7 +744,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio $test->assertSame('test', $clientEncryption->decrypt($encrypted)); $test->expectException(RuntimeException::class); - $test->expectExceptionMessageMatches('#parse error#'); + $test->expectExceptionMessageMatches('#doesnotexist.invalid#'); $clientEncryptionInvalid->createDataKey('azure', ['masterKey' => $azureMasterKey]); }, ]; @@ -756,7 +756,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio $test->assertSame('test', $clientEncryption->decrypt($encrypted)); $test->expectException(RuntimeException::class); - $test->expectExceptionMessageMatches('#parse error#'); + $test->expectExceptionMessageMatches('#doesnotexist.invalid#'); $clientEncryptionInvalid->createDataKey('gcp', ['masterKey' => $gcpMasterKey]); }, ]; @@ -764,7 +764,7 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio yield 'Test 9' => [ static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($gcpMasterKey): void { $masterKey = $gcpMasterKey; - $masterKey['endpoint'] = 'example.com:443'; + $masterKey['endpoint'] = 'doesnotexist.invalid:443'; $test->expectException(RuntimeException::class); $test->expectExceptionMessageMatches('#Invalid KMS response#'); From 7797a7d874b42eec94785e3ef7e310ca9352d654 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 11 Feb 2022 15:58:23 -0500 Subject: [PATCH 110/321] PHPLIB-786: Rename "Versioned API" to "Stable API" in docs (#888) --- ...goDBClient-method-construct-driverOptions.yaml | 2 +- docs/tutorial.txt | 2 +- .../{versioned-api.txt => stable-api.txt} | 15 +++++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) rename docs/tutorial/{versioned-api.txt => stable-api.txt} (90%) diff --git a/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml b/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml index f47e56ba1..5d30540d8 100644 --- a/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml @@ -45,7 +45,7 @@ name: serverApi type: :php:`MongoDB\\Driver\\ServerApi ` description: | Used to declare an API version on the client. See the - :manual:`Versioned API tutorial ` for usage. + :manual:`Stable API tutorial ` for usage. .. versionadded:: 1.9 interface: phpmethod diff --git a/docs/tutorial.txt b/docs/tutorial.txt index 6ad6400ab..cca3ee345 100644 --- a/docs/tutorial.txt +++ b/docs/tutorial.txt @@ -15,4 +15,4 @@ Tutorials /tutorial/indexes /tutorial/tailable-cursor /tutorial/example-data - /tutorial/versioned-api + /tutorial/stable-api diff --git a/docs/tutorial/versioned-api.txt b/docs/tutorial/stable-api.txt similarity index 90% rename from docs/tutorial/versioned-api.txt rename to docs/tutorial/stable-api.txt index ebe971d11..1220f0326 100644 --- a/docs/tutorial/versioned-api.txt +++ b/docs/tutorial/stable-api.txt @@ -1,6 +1,6 @@ -============= -Versioned API -============= +========== +Stable API +========== .. default-domain:: mongodb @@ -10,7 +10,7 @@ Versioned API :depth: 1 :class: singlecol -Declaring an API version +Declaring an API Version ------------------------ To declare an API version, pass a ``serverApi`` driver option when creating your @@ -43,10 +43,9 @@ Strict API ---------- By default, declaring an API version guarantees behavior for commands that are -part of the versioned API, but does not forbid using commands that are not part +part of the stable API, but does not forbid using commands that are not part of the API version. To only allow commands and options that are part of the -versioned API, specify the ``strict`` option when creating the -specify the ``strict`` option when creating the +stable API, specify the ``strict`` option when creating the :php:`MongoDB\\Driver\\ServerApi ` instance: .. code-block:: php @@ -83,7 +82,7 @@ testing to ensure a smooth transition to a future API version. At the time of this writing, no part of API version "1" has been deprecated. -Usage with the command helper +Usage with the Command Helper ----------------------------- When using the :phpmethod:`MongoDB\\Database::command()` method to run arbitrary From 117108ae7785b8b649a805eeb845786d35c546bf Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 15 Feb 2022 15:59:04 -0500 Subject: [PATCH 111/321] PHPLIB-776: Remove references to CSFLE secrets (#890) These secrets are only configured for Evergreen and not GitHub actions. --- .github/workflows/tests.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9a9f32c4f..dc6580c4f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -101,10 +101,3 @@ jobs: env: SYMFONY_DEPRECATIONS_HELPER: 999999 MONGODB_URI: ${{ steps.setup-mongodb.outputs.cluster-uri }} - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} - AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} - AZURE_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} - GCP_EMAIL: ${{ secrets.GCP_EMAIL }} - GCP_PRIVATE_KEY: ${{ secrets.GCP_PRIVATE_KEY }} From 65bbd42b6c9e074ee02dc241af303cb48bd00608 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 18 Feb 2022 10:03:40 -0500 Subject: [PATCH 112/321] PHPLIB-528, PHPLIB-788: Use Session::isDirty() and update session spec tests (#889) * PHPLIB-528: Use Session::isDirty() for spec test assertions * PHPLIB-788: Update session spec tests Synced with mongodb/specifications@e11c1e4459428e765c18ac40099596329a0a83f4 --- .evergreen/config.yml | 14 +- .github/workflows/coding-standards.yml | 2 +- .github/workflows/tests.yml | 8 +- composer.json | 2 +- tests/UnifiedSpecTests/Context.php | 18 - .../UnifiedSpecTests/DirtySessionObserver.php | 84 -- tests/UnifiedSpecTests/Operation.php | 25 +- .../driver-sessions-dirty-session-errors.json | 969 ++++++++++++++++++ .../driver-sessions-server-support.json | 256 +++++ 9 files changed, 1245 insertions(+), 133 deletions(-) delete mode 100644 tests/UnifiedSpecTests/DirtySessionObserver.php create mode 100644 tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json create mode 100644 tests/UnifiedSpecTests/sessions/driver-sessions-server-support.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 1aea04577..15e91dad4 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -608,14 +608,20 @@ axes: - id: driver-versions display_name: Driver Version values: + # TODO: Update to "1.13.0" once PHPC 1.13.0 is released - id: "oldest-supported" - display_name: "1.12.0" + # display_name: "1.13.0" + display_name: "1.13-dev (master)" variables: - EXTENSION_VERSION: "1.12.0" + # EXTENSION_VERSION: "1.13.0" + EXTENSION_BRANCH: "master" + # TODO: Update to "1.13.x"/"stable" once PHPC 1.13.0 is released - id: "latest-stable" - display_name: "1.12.x" + # display_name: "1.13.x" + display_name: "1.13-dev (master)" variables: - EXTENSION_VERSION: "stable" + # EXTENSION_VERSION: "stable" + EXTENSION_BRANCH: "master" - id: "latest-dev" display_name: "1.13-dev (master)" variables: diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 0a584a558..27f53b834 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -20,7 +20,7 @@ jobs: php-version: - "7.4" driver-version: - - "stable" + - "mongodb/mongo-php-driver@master" steps: - name: "Checkout" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dc6580c4f..dae42b290 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,24 +27,24 @@ jobs: mongodb-version: - "4.4" driver-version: - - "stable" + - "mongodb/mongo-php-driver@master" topology: - "server" include: - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "5.0" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "server" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "replica_set" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "sharded_cluster" steps: diff --git a/composer.json b/composer.json index 1e70ade99..edfa98f60 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.2 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.12.0", + "ext-mongodb": "^1.13.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index e8e56189e..9b08a4fee 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -17,7 +17,6 @@ use function current; use function explode; use function implode; -use function in_array; use function key; use function parse_url; use function PHPUnit\Framework\assertArrayHasKey; @@ -50,9 +49,6 @@ final class Context /** @var string */ private $activeClient; - /** @var string[] */ - private $dirtySessions = []; - /** @var EntityMap */ private $entityMap; @@ -134,20 +130,6 @@ public function getInternalClient(): Client return $this->internalClient; } - public function isDirtySession(string $sessionId): bool - { - return in_array($sessionId, $this->dirtySessions); - } - - public function markDirtySession(string $sessionId): void - { - if ($this->isDirtySession($sessionId)) { - return; - } - - $this->dirtySessions[] = $sessionId; - } - public function isActiveClient(string $clientId): bool { return $this->activeClient === $clientId; diff --git a/tests/UnifiedSpecTests/DirtySessionObserver.php b/tests/UnifiedSpecTests/DirtySessionObserver.php deleted file mode 100644 index 928037812..000000000 --- a/tests/UnifiedSpecTests/DirtySessionObserver.php +++ /dev/null @@ -1,84 +0,0 @@ -lsid = $lsid; - } - - /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php - */ - public function commandFailed(CommandFailedEvent $event): void - { - if (! in_array($event->getRequestId(), $this->requestIds)) { - return; - } - - if ($event->getError() instanceof ConnectionException) { - $this->observedNetworkError = true; - } - } - - /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php - */ - public function commandStarted(CommandStartedEvent $event): void - { - if ($this->lsid == ($event->getCommand()->lsid ?? null)) { - $this->requestIds[] = $event->getRequestId(); - } - } - - /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php - */ - public function commandSucceeded(CommandSucceededEvent $event): void - { - } - - public function observedNetworkError(): bool - { - return $this->observedNetworkError; - } - - public function start(): void - { - addSubscriber($this); - } - - public function stop(): void - { - removeSubscriber($this); - } -} diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index d5991f6ce..e69ce46c8 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -137,11 +137,6 @@ public function assert(bool $rethrowExceptions = false): void $result = null; $saveResultAsEntity = null; - if (isset($this->arguments['session'])) { - $dirtySessionObserver = new DirtySessionObserver($this->entityMap->getLogicalSessionId($this->arguments['session'])); - $dirtySessionObserver->start(); - } - try { $result = $this->execute(); $saveResultAsEntity = $this->saveResultAsEntity; @@ -160,14 +155,6 @@ public function assert(bool $rethrowExceptions = false): void $error = $e; } - if (isset($dirtySessionObserver)) { - $dirtySessionObserver->stop(); - - if ($dirtySessionObserver->observedNetworkError()) { - $this->context->markDirtySession($this->arguments['session']); - } - } - if (! $this->ignoreResultAndError) { $this->expectError->assert($error); $this->expectResult->assert($result, $saveResultAsEntity); @@ -744,16 +731,12 @@ private function executeForTestRunner() Assert::fail('Tests using assertNumberConnectionsCheckedOut should be skipped'); break; case 'assertSessionDirty': - /* Context::isDirtySession() requires the session ID. Avoid - * checking $args['session'], which is already resolved. */ - assertArrayHasKey('session', $this->arguments); - assertTrue($this->context->isDirtySession($this->arguments['session'])); + assertArrayHasKey('session', $args); + assertTrue($args['session']->isDirty()); break; case 'assertSessionNotDirty': - /* Context::isDirtySession() requires the session ID. Avoid - * checking $args['session'], which is already resolved. */ - assertArrayHasKey('session', $this->arguments); - assertFalse($this->context->isDirtySession($this->arguments['session'])); + assertArrayHasKey('session', $args); + assertFalse($args['session']->isDirty()); break; case 'assertSessionPinned': assertArrayHasKey('session', $args); diff --git a/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json b/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json new file mode 100644 index 000000000..88a9171db --- /dev/null +++ b/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json @@ -0,0 +1,969 @@ +{ + "description": "driver-sessions-dirty-session-errors", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "4.0", + "topologies": [ + "replicaset" + ] + }, + { + "minServerVersion": "4.1.8", + "topologies": [ + "sharded-replicaset" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "session-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "Dirty explicit session is discarded (insert)", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "closeConnection": true + } + } + } + }, + { + "name": "assertSessionNotDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 2 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 2 + } + } + } + }, + { + "name": "assertSessionDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 3 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 3 + } + } + } + }, + { + "name": "assertSessionDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "endSession", + "object": "session0" + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertDifferentLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": 1 + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": 1 + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 3 + } + ], + "ordered": true, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": 2 + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + } + ] + }, + { + "description": "Dirty explicit session is discarded (findAndModify)", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "closeConnection": true + } + } + } + }, + { + "name": "assertSessionNotDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "session": "session0", + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "Before" + }, + "expectResult": { + "_id": 1 + } + }, + { + "name": "assertSessionDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "endSession", + "object": "session0" + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertDifferentLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "new": false, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": 1, + "readConcern": { + "$$exists": false + }, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "findAndModify", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "new": false, + "lsid": { + "$$sessionLsid": "session0" + }, + "txnNumber": 1, + "readConcern": { + "$$exists": false + }, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "findAndModify", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1, + "x": 1 + } + ] + } + ] + }, + { + "description": "Dirty implicit session is discarded (insert)", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "closeConnection": true + } + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 2 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 2 + } + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertDifferentLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "lsid": { + "$$type": "object" + }, + "txnNumber": 1 + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "lsid": { + "$$type": "object" + }, + "txnNumber": 1 + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "Dirty implicit session is discarded (findAndModify)", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "findAndModify" + ], + "closeConnection": true + } + } + } + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "returnDocument": "Before" + }, + "expectResult": { + "_id": 1 + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertDifferentLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "new": false, + "lsid": { + "$$type": "object" + }, + "txnNumber": 1, + "readConcern": { + "$$exists": false + }, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "findAndModify", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "findAndModify": "test", + "query": { + "_id": 1 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "new": false, + "lsid": { + "$$type": "object" + }, + "txnNumber": 1, + "readConcern": { + "$$exists": false + }, + "writeConcern": { + "$$exists": false + } + }, + "commandName": "findAndModify", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1, + "x": 1 + } + ] + } + ] + }, + { + "description": "Dirty implicit session is discarded (read returning cursor)", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + } + } + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "_id": 1 + } + } + ] + }, + "expectResult": [ + { + "_id": 1 + } + ] + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertDifferentLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$project": { + "_id": 1 + } + } + ], + "lsid": { + "$$type": "object" + } + }, + "commandName": "aggregate", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$project": { + "_id": 1 + } + } + ], + "lsid": { + "$$type": "object" + } + }, + "commandName": "aggregate", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "Dirty implicit session is discarded (read not returning cursor)", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "aggregate" + ], + "closeConnection": true + } + } + } + }, + { + "name": "countDocuments", + "object": "collection0", + "arguments": { + "filter": {} + }, + "expectResult": 1 + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertDifferentLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$match": {} + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "lsid": { + "$$type": "object" + } + }, + "commandName": "aggregate", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$match": {} + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "lsid": { + "$$type": "object" + } + }, + "commandName": "aggregate", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/sessions/driver-sessions-server-support.json b/tests/UnifiedSpecTests/sessions/driver-sessions-server-support.json new file mode 100644 index 000000000..55312b32e --- /dev/null +++ b/tests/UnifiedSpecTests/sessions/driver-sessions-server-support.json @@ -0,0 +1,256 @@ +{ + "description": "driver-sessions-server-support", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "session-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "Server supports explicit sessions", + "operations": [ + { + "name": "assertSessionNotDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 2 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 2 + } + } + } + }, + { + "name": "assertSessionNotDirty", + "object": "testRunner", + "arguments": { + "session": "session0" + } + }, + { + "name": "endSession", + "object": "session0" + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertSameLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "lsid": { + "$$sessionLsid": "session0" + } + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$sessionLsid": "session0" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "Server supports implicit sessions", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2 + } + }, + "expectResult": { + "$$unsetOrMatches": { + "insertedId": { + "$$unsetOrMatches": 2 + } + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": -1 + } + }, + "expectResult": [] + }, + { + "name": "assertSameLsidOnLastTwoCommands", + "object": "testRunner", + "arguments": { + "client": "client0" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2 + } + ], + "ordered": true, + "lsid": { + "$$type": "object" + } + }, + "commandName": "insert", + "databaseName": "session-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": -1 + }, + "lsid": { + "$$type": "object" + } + }, + "commandName": "find", + "databaseName": "session-tests" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "test", + "databaseName": "session-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} From 8796589fd6755beccc5e7b2d5a7f9abf36f77af7 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 24 Feb 2022 19:54:12 -0500 Subject: [PATCH 113/321] PHPLIB-717: Test serverless with load balancer (#892) --- .evergreen/config.yml | 43 ++++++------ .evergreen/serverless/create-instance.sh | 87 ------------------------ .evergreen/serverless/delete-instance.sh | 40 ----------- .evergreen/serverless/get-instance.sh | 37 ---------- tests/FunctionalTestCase.php | 7 +- 5 files changed, 25 insertions(+), 189 deletions(-) delete mode 100755 .evergreen/serverless/create-instance.sh delete mode 100755 .evergreen/serverless/delete-instance.sh delete mode 100755 .evergreen/serverless/get-instance.sh diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 15e91dad4..5a71ebb63 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -203,16 +203,13 @@ functions: - command: shell.exec params: working_dir: "src" - shell: bash - script: |- + script: | ${PREPARE_SHELL} - export PROJECT=${PROJECT} - export SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} - export SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} - export SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} - export SERVERLESS_ATLAS_USER=${SERVERLESS_ATLAS_USER} - export SERVERLESS_ATLAS_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} - bash ${PROJECT_DIRECTORY}/.evergreen/serverless/create-instance.sh + LOADBALANCED=ON \ + SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \ + SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \ + SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \ + bash ${DRIVERS_TOOLS}/.evergreen/serverless/create-instance.sh - command: expansions.update params: file: src/serverless-expansion.yml @@ -220,16 +217,15 @@ functions: "delete serverless instance": - command: shell.exec params: - shell: bash - script: |- - set -o errexit - export SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} - export SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} - export SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} - export SERVERLESS_ATLAS_USER=${SERVERLESS_ATLAS_USER} - export SERVERLESS_ATLAS_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} - export SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} - bash ${PROJECT_DIRECTORY}/.evergreen/serverless/delete-instance.sh + script: | + # Only run if a serverless instance was started + if [ -n "${SERVERLESS_INSTANCE_NAME}" ]; then + SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \ + SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \ + SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \ + SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} \ + bash ${DRIVERS_TOOLS}/.evergreen/serverless/delete-instance.sh + fi "run tests": - command: shell.exec @@ -269,8 +265,7 @@ functions: type: test params: working_dir: "src" - shell: bash - script: |- + script: | ${PREPARE_SHELL} export MONGODB_IS_SERVERLESS=on export MONGODB_USERNAME=${SERVERLESS_ATLAS_USER} @@ -396,6 +391,7 @@ post: # - func: "upload working dir" - func: "upload mo artifacts" - func: "upload test results" + - func: "delete serverless instance" - func: "stop load balancer" - func: "stop mongo-orchestration" - func: "cleanup" @@ -494,10 +490,9 @@ tasks: tags: ["serverless"] commands: - func: "create serverless instance" - vars: - PROJECT: "mongo-php-library" - func: "run serverless tests" - - func: "delete serverless instance" + vars: + MONGODB_URI: "${SINGLE_ATLASPROXY_SERVERLESS_URI}" - name: "test-loadBalanced" tags: ["loadbalanced"] diff --git a/.evergreen/serverless/create-instance.sh b/.evergreen/serverless/create-instance.sh deleted file mode 100755 index 0a56c8e33..000000000 --- a/.evergreen/serverless/create-instance.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash - -set -o errexit -set +o xtrace # disable xtrace to ensure credentials aren't leaked - -if [ -z "$PROJECT" ]; then - echo "Project name must be provided via PROJECT environment variable" - exit 1 -fi -INSTANCE_NAME="$RANDOM-$PROJECT" - -if [ -z "$SERVERLESS_DRIVERS_GROUP" ]; then - echo "Drivers Atlas group must be provided via SERVERLESS_DRIVERS_GROUP environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_API_PRIVATE_KEY" ]; then - echo "Atlas API private key must be provided via SERVERLESS_API_PRIVATE_KEY environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_API_PUBLIC_KEY" ]; then - echo "Atlas API public key must be provided via SERVERLESS_API_PUBLIC_KEY environment variable" - exit 1 -fi - -echo "creating new serverless instance \"${INSTANCE_NAME}\"..." - -DIR=$(dirname $0) -API_BASE_URL="https://account-dev.mongodb.com/api/atlas/v1.0/groups/$SERVERLESS_DRIVERS_GROUP" - -curl \ - -u "$SERVERLESS_API_PUBLIC_KEY:$SERVERLESS_API_PRIVATE_KEY" \ - --silent \ - --show-error \ - -X POST \ - --digest \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - "$API_BASE_URL/serverless?pretty=true" \ - --data " - { - \"name\" : \"${INSTANCE_NAME}\", - \"providerSettings\" : { - \"providerName\": \"SERVERLESS\", - \"backingProviderName\": \"GCP\", - \"instanceSizeName\" : \"SERVERLESS_V2\", - \"regionName\" : \"CENTRAL_US\" - } - }" - -echo "" - -if [ "Windows_NT" = "$OS" ]; then - PYTHON_BINARY=C:/python/Python38/python.exe -else - PYTHON_BINARY=python -fi - -SECONDS=0 -while [ true ]; do - API_RESPONSE=`SERVERLESS_INSTANCE_NAME=$INSTANCE_NAME bash $DIR/get-instance.sh` - STATE_NAME=`echo $API_RESPONSE | $PYTHON_BINARY -c "import sys, json; print(json.load(sys.stdin)['stateName'])" | tr -d '\r\n'` - - if [ "$STATE_NAME" = "IDLE" ]; then - duration="$SECONDS" - echo "setup done! ($(($duration / 60))m $(($duration % 60))s elapsed)" - echo "SERVERLESS_INSTANCE_NAME=\"$INSTANCE_NAME\"" - SRV_ADDRESS=$(echo $API_RESPONSE | $PYTHON_BINARY -c "import sys, json; print(json.load(sys.stdin)['connectionStrings']['standardSrv'])" | tr -d '\r\n') - echo "MONGODB_SRV_URI=\"$SRV_ADDRESS\"" - STANDARD_ADDRESS=$(echo $API_RESPONSE | $PYTHON_BINARY -c "import sys, json; print(json.load(sys.stdin)['connectionStrings']['standard'].replace('&authSource=admin', ''))" | tr -d '\r\n') - echo "MONGODB_URI=\"$STANDARD_ADDRESS\"" - cat < serverless-expansion.yml -MONGODB_URI: "$STANDARD_ADDRESS" -MONGODB_SRV_URI: "$SRV_ADDRESS" -SERVERLESS_INSTANCE_NAME: "$INSTANCE_NAME" -SSL: ssl -AUTH: auth -TOPOLOGY: sharded_cluster -SERVERLESS: serverless -EOF - exit 0 - else - echo "setup still in progress, status=$STATE_NAME, sleeping for 1 minute..." - sleep 60 - fi -done diff --git a/.evergreen/serverless/delete-instance.sh b/.evergreen/serverless/delete-instance.sh deleted file mode 100755 index ba412d4d4..000000000 --- a/.evergreen/serverless/delete-instance.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -set -o errexit -set +o xtrace - -if [ -z "$SERVERLESS_INSTANCE_NAME" ]; then - echo "Instance name must be provided via SERVERLESS_INSTANCE_NAME environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_DRIVERS_GROUP" ]; then - echo "Drivers Atlas group must be provided via SERVERLESS_DRIVERS_GROUP environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_API_PRIVATE_KEY" ]; then - echo "Atlas API private key must be provided via SERVERLESS_API_PRIVATE_KEY environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_API_PUBLIC_KEY" ]; then - echo "Atlas API public key must be provided via SERVERLESS_API_PUBLIC_KEY environment variable" - exit 1 -fi - -echo "deleting serverless instance \"${SERVERLESS_INSTANCE_NAME}\"..." - -API_BASE_URL="https://account-dev.mongodb.com/api/atlas/v1.0/groups/$SERVERLESS_DRIVERS_GROUP" - -curl \ - --silent \ - --show-error \ - -u "$SERVERLESS_API_PUBLIC_KEY:$SERVERLESS_API_PRIVATE_KEY" \ - -X DELETE \ - --digest \ - --header "Accept: application/json" \ - --header "Content-Type: application/json" \ - "${API_BASE_URL}/serverless/${SERVERLESS_INSTANCE_NAME}?pretty=true" - -echo "" diff --git a/.evergreen/serverless/get-instance.sh b/.evergreen/serverless/get-instance.sh deleted file mode 100755 index 496400dc7..000000000 --- a/.evergreen/serverless/get-instance.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -set -o errexit -set +o xtrace - -if [ -z "$SERVERLESS_INSTANCE_NAME" ]; then - echo "Instance name must be provided via SERVERLESS_INSTANCE_NAME environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_DRIVERS_GROUP" ]; then - echo "Drivers Atlas group must be provided via SERVERLESS_DRIVERS_GROUP environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_API_PRIVATE_KEY" ]; then - echo "Atlas API private key must be provided via SERVERLESS_API_PRIVATE_KEY environment variable" - exit 1 -fi - -if [ -z "$SERVERLESS_API_PUBLIC_KEY" ]; then - echo "Atlas API public key must be provided via SERVERLESS_API_PUBLIC_KEY environment variable" - exit 1 -fi - -API_BASE_URL="https://account-dev.mongodb.com/api/private/nds/serverless/groups/$SERVERLESS_DRIVERS_GROUP" - -curl \ - --silent \ - --show-error \ - -u "$SERVERLESS_API_PUBLIC_KEY:$SERVERLESS_API_PRIVATE_KEY" \ - -X GET \ - --digest \ - --header "Accept: application/json" \ - "${API_BASE_URL}/instances/${SERVERLESS_INSTANCE_NAME}?pretty=true" \ - -echo "" diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 2dd2d6ee3..b296f3b8e 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -423,7 +423,7 @@ protected function isShardedCluster() return true; } - // Assume that load balancers are properly configured and front mongos + // Assume that load balancers are properly configured and front sharded clusters if ($type == Server::TYPE_LOAD_BALANCER) { return true; } @@ -433,6 +433,11 @@ protected function isShardedCluster() protected function isShardedClusterUsingReplicasets() { + // Assume serverless is a sharded cluster using replica sets + if (static::isServerless()) { + return true; + } + $cursor = $this->getPrimaryServer()->executeQuery( 'config.shards', new Query([], ['limit' => 1]) From b032a8267776c7f7b9ccc4986625b7be10a64d2a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 25 Feb 2022 13:22:26 -0500 Subject: [PATCH 114/321] PHPLIB-798: Use more flexible assertions for connection counts (#894) --- tests/SpecTests/PrimaryStepDownSpecTest.php | 31 +++++++++++++-------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php index 36dacd06f..48aa55cc0 100644 --- a/tests/SpecTests/PrimaryStepDownSpecTest.php +++ b/tests/SpecTests/PrimaryStepDownSpecTest.php @@ -43,7 +43,7 @@ public function setUp(): void } /** - * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id10 + * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#not-primary-keep-connection-pool */ public function testNotPrimaryKeepsConnectionPool(): void { @@ -79,7 +79,7 @@ public function testNotPrimaryKeepsConnectionPool(): void } /** - * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id11 + * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#not-primary-reset-connection-pool */ public function testNotPrimaryResetConnectionPool(): void { @@ -106,8 +106,11 @@ public function testNotPrimaryResetConnectionPool(): void $this->assertSame(self::NOT_PRIMARY, $e->getCode()); } - // Verify that the connection pool has been cleared - $this->assertSame($totalConnectionsCreated + 1, $this->getTotalConnectionsCreated()); + /* Verify that the connection pool has been cleared and that a new + * connection has been created. Use ">=" to allow for the possibility + * that the server created additional connections unrelated to this + * test. */ + $this->assertGreaterThanOrEqual($totalConnectionsCreated + 1, $this->getTotalConnectionsCreated()); // Execute an insert into the test collection of a {test: 1} document and verify that it succeeds. $result = $this->insertDocuments(1); @@ -115,7 +118,7 @@ public function testNotPrimaryResetConnectionPool(): void } /** - * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id12 + * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#shutdown-in-progress-reset-connection-pool */ public function testShutdownResetConnectionPool(): void { @@ -142,8 +145,11 @@ public function testShutdownResetConnectionPool(): void $this->assertSame(self::SHUTDOWN_IN_PROGRESS, $e->getCode()); } - // Verify that the connection pool has been cleared - $this->assertSame($totalConnectionsCreated + 1, $this->getTotalConnectionsCreated()); + /* Verify that the connection pool has been cleared and that a new + * connection has been created. Use ">=" to allow for the possibility + * that the server created additional connections unrelated to this + * test. */ + $this->assertGreaterThanOrEqual($totalConnectionsCreated + 1, $this->getTotalConnectionsCreated()); // Execute an insert into the test collection of a {test: 1} document and verify that it succeeds. $result = $this->insertDocuments(1); @@ -151,7 +157,7 @@ public function testShutdownResetConnectionPool(): void } /** - * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id13 + * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#interrupted-at-shutdown-reset-connection-pool */ public function testInterruptedAtShutdownResetConnectionPool(): void { @@ -178,8 +184,11 @@ public function testInterruptedAtShutdownResetConnectionPool(): void $this->assertSame(self::INTERRUPTED_AT_SHUTDOWN, $e->getCode()); } - // Verify that the connection pool has been cleared - $this->assertSame($totalConnectionsCreated + 1, $this->getTotalConnectionsCreated()); + /* Verify that the connection pool has been cleared and that a new + * connection has been created. Use ">=" to allow for the possibility + * that the server created additional connections unrelated to this + * test. */ + $this->assertGreaterThanOrEqual($totalConnectionsCreated + 1, $this->getTotalConnectionsCreated()); // Execute an insert into the test collection of a {test: 1} document and verify that it succeeds. $result = $this->insertDocuments(1); @@ -187,7 +196,7 @@ public function testInterruptedAtShutdownResetConnectionPool(): void } /** - * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#id9 + * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#getmore-iteration */ public function testGetMoreIteration(): void { From 103c1f2ea5c3099a7fccd5b22eabf33fa5eae5a7 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 28 Feb 2022 22:50:45 -0500 Subject: [PATCH 115/321] PHPLIB-795, PHPLIB-796: Remove references to pre-3.6 servers (#893) * Remove pre-3.6 server versions from Evergreen matrix * Remove references to unsupported pre-3.6 features in docs * Remove version checks for pre-3.6 servers Preserve behavior for only sending bypassDocumentValidation if true. This also removes a reference to an undeclared var in ModifyCollection (PHPLIB-796). * Remove skipped tests for pre-3.6 servers --- .evergreen/config.yml | 16 +-- .../apiargs-MongoDBClient-common-option.yaml | 3 - ...goDBClient-method-dropDatabase-option.yaml | 3 - ...iargs-MongoDBCollection-common-option.yaml | 9 -- ...oDBCollection-method-aggregate-option.yaml | 3 - ...BCollection-method-createIndex-option.yaml | 3 - ...ollection-method-createIndexes-option.yaml | 3 - ...-MongoDBCollection-method-drop-option.yaml | 3 - ...oDBCollection-method-dropIndex-option.yaml | 3 - ...BCollection-method-dropIndexes-option.yaml | 3 - ...ection-method-findOneAndDelete-option.yaml | 3 - ...ction-method-findOneAndReplace-option.yaml | 3 - ...ection-method-findOneAndUpdate-option.yaml | 3 - ...ongoDBCollection-method-rename-option.yaml | 3 - ...apiargs-MongoDBDatabase-common-option.yaml | 3 - ...ngoDBDatabase-method-aggregate-option.yaml | 3 - ...tabase-method-createCollection-option.yaml | 3 - ...gs-MongoDBDatabase-method-drop-option.yaml | 3 - ...Database-method-dropCollection-option.yaml | 3 - ...tabase-method-renameCollection-option.yaml | 3 - docs/includes/apiargs-aggregate-option.yaml | 3 - docs/includes/apiargs-common-option.yaml | 5 - docs/reference/exception-classes.txt | 6 - .../method/MongoDBCollection-count.txt | 3 +- .../MongoDBCollection-countDocuments.txt | 2 +- .../MongoDBDatabase-createCollection.txt | 8 +- src/Client.php | 10 +- src/Collection.php | 51 +++------ src/Command/ListCollections.php | 2 - src/Command/ListDatabases.php | 4 - src/Database.php | 26 ++--- src/Exception/UnsupportedException.php | 6 + src/Operation/Aggregate.php | 65 +++-------- src/Operation/BulkWrite.php | 108 ++++++------------ src/Operation/Count.php | 25 +--- src/Operation/CountDocuments.php | 8 -- src/Operation/CreateCollection.php | 25 ---- src/Operation/CreateIndexes.php | 28 +---- src/Operation/DatabaseCommand.php | 2 - src/Operation/Delete.php | 22 +--- src/Operation/DeleteMany.php | 5 - src/Operation/DeleteOne.php | 5 - src/Operation/Distinct.php | 25 +--- src/Operation/DropCollection.php | 27 +---- src/Operation/DropDatabase.php | 15 --- src/Operation/DropIndexes.php | 15 +-- src/Operation/EstimatedDocumentCount.php | 5 - src/Operation/Explain.php | 14 --- src/Operation/Find.php | 32 +----- src/Operation/FindAndModify.php | 60 ++-------- src/Operation/FindOne.php | 8 -- src/Operation/FindOneAndDelete.php | 8 -- src/Operation/FindOneAndReplace.php | 11 -- src/Operation/FindOneAndUpdate.php | 11 -- src/Operation/InsertMany.php | 46 ++++---- src/Operation/InsertOne.php | 46 ++++---- src/Operation/ListCollectionNames.php | 2 - src/Operation/ListCollections.php | 2 - src/Operation/ListDatabaseNames.php | 4 - src/Operation/ListDatabases.php | 4 - src/Operation/ListIndexes.php | 2 - src/Operation/MapReduce.php | 59 ++-------- src/Operation/ModifyCollection.php | 11 -- src/Operation/RenameCollection.php | 15 +-- src/Operation/ReplaceOne.php | 8 -- src/Operation/Update.php | 80 +++++-------- src/Operation/UpdateMany.php | 11 -- src/Operation/UpdateOne.php | 11 -- src/Operation/Watch.php | 2 - tests/ClientFunctionalTest.php | 5 - tests/Collection/CollectionFunctionalTest.php | 4 - tests/DocumentationExamplesTest.php | 4 - tests/FunctionalTestCase.php | 34 +----- tests/Model/IndexInfoFunctionalTest.php | 10 +- tests/Operation/AggregateFunctionalTest.php | 42 ------- tests/Operation/BulkWriteFunctionalTest.php | 12 -- tests/Operation/CountFunctionalTest.php | 14 +-- .../CreateCollectionFunctionalTest.php | 6 - .../Operation/CreateIndexesFunctionalTest.php | 4 - .../DatabaseCommandFunctionalTest.php | 6 - tests/Operation/DeleteFunctionalTest.php | 24 ---- tests/Operation/DistinctFunctionalTest.php | 5 - .../DropCollectionFunctionalTest.php | 6 - .../Operation/DropDatabaseFunctionalTest.php | 5 - tests/Operation/DropIndexesFunctionalTest.php | 5 - tests/Operation/ExplainFunctionalTest.php | 32 ------ .../Operation/FindAndModifyFunctionalTest.php | 12 -- tests/Operation/FindFunctionalTest.php | 9 -- tests/Operation/InsertManyFunctionalTest.php | 14 --- tests/Operation/InsertOneFunctionalTest.php | 14 --- .../ListCollectionNamesFunctionalTest.php | 6 - .../ListCollectionsFunctionalTest.php | 10 -- .../ListDatabaseNamesFunctionalTest.php | 10 -- .../Operation/ListDatabasesFunctionalTest.php | 10 -- tests/Operation/ListIndexesFunctionalTest.php | 6 - tests/Operation/MapReduceFunctionalTest.php | 12 -- .../RenameCollectionFunctionalTest.php | 20 +--- tests/Operation/UpdateFunctionalTest.php | 32 ------ .../Constraint/MatchesTest.php | 5 - 99 files changed, 202 insertions(+), 1208 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 5a71ebb63..b15f1b713 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -575,18 +575,6 @@ axes: display_name: "3.6" variables: VERSION: "3.6" - - id: "3.4" - display_name: "3.4" - variables: - VERSION: "3.4" - - id: "3.2" - display_name: "3.2" - variables: - VERSION: "3.2" - - id: "3.0" - display_name: "3.0" - variables: - VERSION: "3.0" - id: edge-versions display_name: MongoDB Version @@ -596,9 +584,9 @@ axes: variables: VERSION: "5.0" - id: "oldest-supported" - display_name: "3.0" + display_name: "3.6" variables: - VERSION: "3.0" + VERSION: "3.6" - id: driver-versions display_name: Driver Version diff --git a/docs/includes/apiargs-MongoDBClient-common-option.yaml b/docs/includes/apiargs-MongoDBClient-common-option.yaml index 89092358f..4ffc52a92 100644 --- a/docs/includes/apiargs-MongoDBClient-common-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-common-option.yaml @@ -4,9 +4,6 @@ type: :php:`MongoDB\\Driver\\ReadConcern ` description: | :manual:`Read concern ` to use for the operation. Defaults to the client's read concern. - - This is not supported for server versions prior to 3.2 and will result in an - exception at execution time if used. interface: phpmethod operation: ~ optional: true diff --git a/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml b/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml index e219c1459..07e75df74 100644 --- a/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml @@ -13,7 +13,4 @@ post: | source: file: apiargs-MongoDBClient-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-common-option.yaml b/docs/includes/apiargs-MongoDBCollection-common-option.yaml index 643308ea5..fb919ea42 100644 --- a/docs/includes/apiargs-MongoDBCollection-common-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-common-option.yaml @@ -4,9 +4,6 @@ type: array description: | An array of filter documents that determines which array elements to modify for an update operation on an array field. - - This is not supported for server versions prior to 3.6 and will result in an - exception at execution time if used. interface: phpmethod operation: ~ optional: true @@ -17,9 +14,6 @@ type: boolean description: | If ``true``, allows the write operation to circumvent document level validation. Defaults to ``false``. - - This option is available in MongoDB 3.2+ and is ignored for older server - versions, which do not support document level validation. interface: phpmethod operation: ~ optional: true @@ -40,9 +34,6 @@ description: | :manual:`Read concern ` to use for the operation. Defaults to the collection's read concern. - This is not supported for server versions prior to 3.2 and will result in an - exception at execution time if used. - It is not possible to specify a :manual:`read concern ` for individual operations as part of a transaction. Instead, set the ``readConcern`` option when starting the diff --git a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml index 6d1f0c434..1d0346daa 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml @@ -78,7 +78,4 @@ source: post: | This only applies when a :ref:`$out ` or :ref:`$merge ` stage is specified. - - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml index 1a76b33ca..18d1ce07e 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml @@ -105,7 +105,4 @@ post: | source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml index 8808ddd1b..5728ab31b 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml @@ -17,7 +17,4 @@ post: | source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml index b1f39752a..3a66ad3b9 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml @@ -13,7 +13,4 @@ post: | source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml index 00db41c6c..9bc36f4bf 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml @@ -19,7 +19,4 @@ post: | source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml index 0b1970c36..0aa5048f2 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml @@ -17,7 +17,4 @@ post: | source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml index 894b51b82..c8a1e58ce 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml @@ -38,7 +38,4 @@ post: | source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.2 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml index 6b282dd29..2987f9b08 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml @@ -59,7 +59,4 @@ source: source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.2 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml index 8393d26aa..d3a6eff42 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml @@ -65,7 +65,4 @@ source: source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.2 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml index e0d9dbf26..3aed74eb2 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml @@ -11,9 +11,6 @@ source: source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. --- arg_name: option name: dropTarget diff --git a/docs/includes/apiargs-MongoDBDatabase-common-option.yaml b/docs/includes/apiargs-MongoDBDatabase-common-option.yaml index 69b4c13da..b03dac7a7 100644 --- a/docs/includes/apiargs-MongoDBDatabase-common-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-common-option.yaml @@ -4,9 +4,6 @@ type: :php:`MongoDB\\Driver\\ReadConcern ` description: | :manual:`Read concern ` to use for the operation. Defaults to the database's read concern. - - This is not supported for server versions prior to 3.2 and will result in an - exception at execution time if used. interface: phpmethod operation: ~ optional: true diff --git a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml index b94d80d48..4d0bf4b25 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml @@ -54,7 +54,4 @@ source: post: | This only applies when a :ref:`$out ` or :ref:`$merge ` stage is specified. - - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index f0f321172..4c341d91e 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -265,7 +265,4 @@ optional: true source: file: apiargs-MongoDBDatabase-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml index 899696857..5b3c18c33 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml @@ -13,7 +13,4 @@ post: | source: file: apiargs-MongoDBDatabase-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml index 899696857..5b3c18c33 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml @@ -13,7 +13,4 @@ post: | source: file: apiargs-MongoDBDatabase-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. ... diff --git a/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml index 973957cf8..bf7d96638 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml @@ -11,9 +11,6 @@ post: | source: file: apiargs-MongoDBDatabase-common-option.yaml ref: writeConcern -post: | - This is not supported for server versions prior to 3.4 and will result in an - exception at execution time if used. --- arg_name: option name: dropTarget diff --git a/docs/includes/apiargs-aggregate-option.yaml b/docs/includes/apiargs-aggregate-option.yaml index 274540449..557cd98fb 100644 --- a/docs/includes/apiargs-aggregate-option.yaml +++ b/docs/includes/apiargs-aggregate-option.yaml @@ -25,9 +25,6 @@ source: post: | This only applies when using the :ref:`$out ` and :ref:`$out ` stages. - - Document validation requires MongoDB 3.2 or later: if you are using an earlier - version of MongoDB, this option will be ignored. --- arg_name: option name: comment diff --git a/docs/includes/apiargs-common-option.yaml b/docs/includes/apiargs-common-option.yaml index 41f918205..6ef2c761e 100644 --- a/docs/includes/apiargs-common-option.yaml +++ b/docs/includes/apiargs-common-option.yaml @@ -8,9 +8,6 @@ description: | mandatory; all other collation fields are optional. For descriptions of the fields, see :manual:`Collation Document `. - - This option is available in MongoDB 3.4+ and will result in an exception at - execution time if specified for an older server version. interface: phpmethod operation: ~ optional: true @@ -68,8 +65,6 @@ name: session type: :php:`MongoDB\\Driver\\Session ` description: | Client session to associate with the operation. - - Sessions are not supported for server versions prior to 3.6. interface: phpmethod operation: ~ optional: true diff --git a/docs/reference/exception-classes.txt b/docs/reference/exception-classes.txt index 289e4ffa4..b5f9fb0b6 100644 --- a/docs/reference/exception-classes.txt +++ b/docs/reference/exception-classes.txt @@ -70,12 +70,6 @@ MongoDB\\Exception\\UnsupportedException selected server. It is used sparingly in cases where silently ignoring the unsupported option might otherwise lead to unexpected behavior. - For example, the ``collation`` option for - :phpmethod:`MongoDB\\Collection::deleteOne()` is only supported by - MongoDB 3.4+. Since collation determines how a document is matched, silently - ignoring the option for an older server version could result in an - unintended document being deleted. - This class extends the library's :phpclass:`RuntimeException ` class. diff --git a/docs/reference/method/MongoDBCollection-count.txt b/docs/reference/method/MongoDBCollection-count.txt index 0c5906304..012b3cb6f 100644 --- a/docs/reference/method/MongoDBCollection-count.txt +++ b/docs/reference/method/MongoDBCollection-count.txt @@ -56,8 +56,7 @@ metadata. Even when provided with a query filter the ``count`` command can return inaccurate results with a sharded cluster if orphaned documents exist or if a chunk migration is in progress. The :phpmethod:`MongoDB\\Collection::countDocuments()` method avoids these sharded -cluster problems entirely when used with MongoDB 3.6+, and when a primary read -preference with older sharded clusters. +cluster problems entirely. .. include:: /includes/extracts/note-bson-comparison.rst diff --git a/docs/reference/method/MongoDBCollection-countDocuments.txt b/docs/reference/method/MongoDBCollection-countDocuments.txt index b66171c27..0b150361f 100644 --- a/docs/reference/method/MongoDBCollection-countDocuments.txt +++ b/docs/reference/method/MongoDBCollection-countDocuments.txt @@ -77,7 +77,7 @@ Consider the following alternatives to these restricted operators: - :query:`$geoWithin` with :query:`$centerSphere` * - :query:`$where` - - :query:`$expr` (requires MongoDB 3.6+) + - :query:`$expr` .. include:: /includes/extracts/note-bson-comparison.rst diff --git a/docs/reference/method/MongoDBDatabase-createCollection.txt b/docs/reference/method/MongoDBDatabase-createCollection.txt index f024806d7..a3e74ef5c 100644 --- a/docs/reference/method/MongoDBDatabase-createCollection.txt +++ b/docs/reference/method/MongoDBDatabase-createCollection.txt @@ -41,11 +41,9 @@ Definition .. include:: /includes/apiargs/MongoDBDatabase-method-createCollection-option.rst - Note that not all options are available on all versions of MongoDB. Document - validation, for example, was added in MongoDB 3.2; similarly, the WiredTiger - storage engine is available only for MongoDB 3.0 and later. Refer to the - :manual:`create ` command reference in the MongoDB - manual for compatibility considerations. + Note that not all options are available on all versions of MongoDB. Refer to + the :manual:`create ` command reference in the + MongoDB manual for compatibility considerations. Return Values ------------- diff --git a/src/Client.php b/src/Client.php index 53611f4e3..a1718ae9c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -51,12 +51,6 @@ class Client 'root' => BSONDocument::class, ]; - /** @var integer */ - private static $wireVersionForReadConcern = 4; - - /** @var integer */ - private static $wireVersionForWritableCommandWriteConcern = 5; - /** @var string */ private static $handshakeSeparator = ' / '; @@ -215,7 +209,7 @@ public function dropDatabase($databaseName, array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -372,7 +366,7 @@ public function watch(array $pipeline = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } diff --git a/src/Collection.php b/src/Collection.php index 3b22de2f5..d25db7105 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -75,15 +75,6 @@ class Collection 'root' => BSONDocument::class, ]; - /** @var integer */ - private static $wireVersionForFindAndModifyWriteConcern = 4; - - /** @var integer */ - private static $wireVersionForReadConcern = 4; - - /** @var integer */ - private static $wireVersionForWritableCommandWriteConcern = 5; - /** @var integer */ private static $wireVersionForReadConcernWithWriteStage = 8; @@ -236,7 +227,6 @@ public function aggregate(array $pipeline, array $options = []) */ if ( ! isset($options['readConcern']) && - server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options) && ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage)) ) { @@ -247,12 +237,7 @@ public function aggregate(array $pipeline, array $options = []) $options['typeMap'] = $this->typeMap; } - if ( - $hasWriteStage && - ! isset($options['writeConcern']) && - server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && - ! is_in_transaction($options) - ) { + if ($hasWriteStage && ! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -306,7 +291,7 @@ public function count($filter = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -335,7 +320,7 @@ public function countDocuments($filter = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -397,7 +382,7 @@ public function createIndexes(array $indexes, array $options = []) { $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -479,7 +464,7 @@ public function distinct($fieldName, $filter = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -506,7 +491,7 @@ public function drop(array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -540,7 +525,7 @@ public function dropIndex($indexName, array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -567,7 +552,7 @@ public function dropIndexes(array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -595,7 +580,7 @@ public function estimatedDocumentCount(array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -653,7 +638,7 @@ public function find($filter = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -686,7 +671,7 @@ public function findOne($filter = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -718,7 +703,7 @@ public function findOneAndDelete($filter, array $options = []) { $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -755,7 +740,7 @@ public function findOneAndReplace($filter, $replacement, array $options = []) { $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -792,7 +777,7 @@ public function findOneAndUpdate($filter, $update, array $options = []) { $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForFindAndModifyWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -986,7 +971,7 @@ public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, * * A read concern is also not compatible with transactions. */ - if (! isset($options['readConcern']) && ! ($hasOutputCollection && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! ($hasOutputCollection && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } @@ -994,7 +979,7 @@ public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, $options['typeMap'] = $this->typeMap; } - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -1027,7 +1012,7 @@ public function rename(string $toCollectionName, ?string $toDatabaseName = null, $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -1135,7 +1120,7 @@ public function watch(array $pipeline = [], array $options = []) * related to change streams being unsupported instead of an * UnsupportedException regarding use of the "readConcern" option from * the Aggregate operation class. */ - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index e3a28d374..2e2d7372a 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -65,8 +65,6 @@ class ListCollections implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param string $databaseName Database name * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index cebddf781..91c793f57 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -54,8 +54,6 @@ class ListDatabases implements Executable * * * filter (document): Query by which to filter databases. * - * For servers < 3.6, this option is ignored. - * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * @@ -65,8 +63,6 @@ class ListDatabases implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ diff --git a/src/Database.php b/src/Database.php index 58daaf41f..b790f90ae 100644 --- a/src/Database.php +++ b/src/Database.php @@ -55,12 +55,6 @@ class Database 'root' => BSONDocument::class, ]; - /** @var integer */ - private static $wireVersionForReadConcern = 4; - - /** @var integer */ - private static $wireVersionForWritableCommandWriteConcern = 5; - /** @var integer */ private static $wireVersionForReadConcernWithWriteStage = 8; @@ -217,7 +211,6 @@ public function aggregate(array $pipeline, array $options = []) */ if ( ! isset($options['readConcern']) && - server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options) && ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage)) ) { @@ -228,12 +221,7 @@ public function aggregate(array $pipeline, array $options = []) $options['typeMap'] = $this->typeMap; } - if ( - $hasWriteStage && - ! isset($options['writeConcern']) && - server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && - ! is_in_transaction($options) - ) { + if ($hasWriteStage && ! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -283,7 +271,7 @@ public function createCollection($collectionName, array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -310,7 +298,7 @@ public function drop(array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -338,7 +326,7 @@ public function dropCollection($collectionName, array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -460,7 +448,7 @@ public function modifyCollection($collectionName, array $collectionOptions, arra $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -494,7 +482,7 @@ public function renameCollection(string $fromCollectionName, string $toCollectio $server = select_server($this->manager, $options); - if (! isset($options['writeConcern']) && server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern) && ! is_in_transaction($options)) { + if (! isset($options['writeConcern']) && ! is_in_transaction($options)) { $options['writeConcern'] = $this->writeConcern; } @@ -561,7 +549,7 @@ public function watch(array $pipeline = [], array $options = []) $server = select_server($this->manager, $options); - if (! isset($options['readConcern']) && server_supports_feature($server, self::$wireVersionForReadConcern) && ! is_in_transaction($options)) { + if (! isset($options['readConcern']) && ! is_in_transaction($options)) { $options['readConcern'] = $this->readConcern; } diff --git a/src/Exception/UnsupportedException.php b/src/Exception/UnsupportedException.php index 779c1c262..de0f7a895 100644 --- a/src/Exception/UnsupportedException.php +++ b/src/Exception/UnsupportedException.php @@ -32,6 +32,9 @@ public static function allowDiskUseNotSupported() /** * Thrown when array filters are not supported by a server. * + * @deprecated 1.12 + * @todo Remove this in 2.0 (see: PHPLIB-797) + * * @return self */ public static function arrayFiltersNotSupported() @@ -42,6 +45,9 @@ public static function arrayFiltersNotSupported() /** * Thrown when collations are not supported by a server. * + * @deprecated 1.12 + * @todo Remove this in 2.0 (see: PHPLIB-797) + * * @return self */ public static function collationNotSupported() diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 7459481ef..6c3596b01 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -40,7 +40,6 @@ use function is_string; use function MongoDB\create_field_path_type_map; use function MongoDB\is_last_pipeline_operator_write; -use function MongoDB\server_supports_feature; use function sprintf; /** @@ -52,18 +51,6 @@ */ class Aggregate implements Executable, Explainable { - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - - /** @var integer */ - private static $wireVersionForReadConcern = 4; - - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var string */ private $databaseName; @@ -97,14 +84,8 @@ class Aggregate implements Executable, Explainable * circumvent document level validation. This only applies when an $out * or $merge stage is specified. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * comment (string): An arbitrary string to help trace the operation * through the database profiler, currentOp, and logs. * @@ -128,17 +109,12 @@ class Aggregate implements Executable, Explainable * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * This option is ignored if an $out or $merge stage is specified. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will be * applied to the returned Cursor (it is not sent to the server). * @@ -151,9 +127,6 @@ class Aggregate implements Executable, Explainable * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only * applies when an $out or $merge stage is specified. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * Note: Collection-agnostic commands (e.g. $currentOp) may be executed by * specifying null for the collection name. * @@ -249,6 +222,10 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr throw new InvalidArgumentException('"batchSize" option should not be used if "useCursor" is false'); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (isset($options['readConcern']) && $options['readConcern']->isDefault()) { unset($options['readConcern']); } @@ -285,23 +262,11 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr * @param Server $server * @return Traversable * @throws UnexpectedValueException if the command response was malformed - * @throws UnsupportedException if collation, read concern, or write concern is used and unsupported + * @throws UnsupportedException if read concern or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) { - throw UnsupportedException::readConcernNotSupported(); - } - - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction) { if (isset($this->options['readConcern'])) { @@ -314,7 +279,7 @@ public function execute(Server $server) } $command = new Command( - $this->createCommandDocument($server), + $this->createCommandDocument(), $this->createCommandOptions() ); @@ -350,24 +315,22 @@ public function execute(Server $server) */ public function getCommandDocument(Server $server) { - return $this->createCommandDocument($server); + return $this->createCommandDocument(); } - private function createCommandDocument(Server $server): array + /** + * Create the aggregate command document. + * + * @return array + */ + private function createCommandDocument() { $cmd = [ 'aggregate' => $this->collectionName ?? 1, 'pipeline' => $this->pipeline, ]; - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - - foreach (['allowDiskUse', 'comment', 'explain', 'maxTimeMS'] as $option) { + foreach (['allowDiskUse', 'bypassDocumentValidation', 'comment', 'explain', 'maxTimeMS'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index 3faa1a960..b37124e66 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -35,7 +35,6 @@ use function key; use function MongoDB\is_first_key_operator; use function MongoDB\is_pipeline; -use function MongoDB\server_supports_feature; use function sprintf; /** @@ -53,15 +52,6 @@ class BulkWrite implements Executable public const UPDATE_MANY = 'updateMany'; public const UPDATE_ONE = 'updateOne'; - /** @var integer */ - private static $wireVersionForArrayFilters = 6; - - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - /** @var string */ private $databaseName; @@ -74,12 +64,6 @@ class BulkWrite implements Executable /** @var array */ private $options; - /** @var boolean */ - private $isArrayFiltersUsed = false; - - /** @var boolean */ - private $isCollationUsed = false; - /** * Constructs a bulk write operation. * @@ -102,16 +86,10 @@ class BulkWrite implements Executable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * Supported options for replaceOne, updateMany, and updateOne operations: * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * @@ -120,25 +98,17 @@ class BulkWrite implements Executable * * arrayFilters (document array): A set of filters specifying to which * array elements an update should apply. * - * This is not supported for server versions < 3.6 and will result in an - * exception at execution time if used. - * * Supported options for the bulk write operation: * * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. The default is false. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * ordered (boolean): If true, when an insert fails, return without * performing the remaining writes. If false, when a write fails, * continue with the remaining writes, if any. The default is true. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name @@ -195,12 +165,8 @@ public function __construct($databaseName, $collectionName, array $operations, a $args[1]['limit'] = ($type === self::DELETE_ONE ? 1 : 0); - if (isset($args[1]['collation'])) { - $this->isCollationUsed = true; - - if (! is_array($args[1]['collation']) && ! is_object($args[1]['collation'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]["collation"]', $i, $type), $args[1]['collation'], 'array or object'); - } + if (isset($args[1]['collation']) && ! is_array($args[1]['collation']) && ! is_object($args[1]['collation'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]["collation"]', $i, $type), $args[1]['collation'], 'array or object'); } $operations[$i][$type][1] = $args[1]; @@ -231,12 +197,8 @@ public function __construct($databaseName, $collectionName, array $operations, a $args[2]['multi'] = false; $args[2] += ['upsert' => false]; - if (isset($args[2]['collation'])) { - $this->isCollationUsed = true; - - if (! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); - } + if (isset($args[2]['collation']) && ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); } if (! is_bool($args[2]['upsert'])) { @@ -272,20 +234,12 @@ public function __construct($databaseName, $collectionName, array $operations, a $args[2]['multi'] = ($type === self::UPDATE_MANY); $args[2] += ['upsert' => false]; - if (isset($args[2]['arrayFilters'])) { - $this->isArrayFiltersUsed = true; - - if (! is_array($args[2]['arrayFilters'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["arrayFilters"]', $i, $type), $args[2]['arrayFilters'], 'array'); - } + if (isset($args[2]['arrayFilters']) && ! is_array($args[2]['arrayFilters'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["arrayFilters"]', $i, $type), $args[2]['arrayFilters'], 'array'); } - if (isset($args[2]['collation'])) { - $this->isCollationUsed = true; - - if (! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { - throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); - } + if (isset($args[2]['collation']) && ! is_array($args[2]['collation']) && ! is_object($args[2]['collation'])) { + throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][2]["collation"]', $i, $type), $args[2]['collation'], 'array or object'); } if (! is_bool($args[2]['upsert'])) { @@ -321,6 +275,10 @@ public function __construct($databaseName, $collectionName, array $operations, a throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { unset($options['writeConcern']); } @@ -337,34 +295,17 @@ public function __construct($databaseName, $collectionName, array $operations, a * @see Executable::execute() * @param Server $server * @return BulkWriteResult - * @throws UnsupportedException if array filters or collation is used and unsupported + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if ($this->isArrayFiltersUsed && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) { - throw UnsupportedException::arrayFiltersNotSupported(); - } - - if ($this->isCollationUsed && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - $options = ['ordered' => $this->options['ordered']]; - - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - - $bulk = new Bulk($options); + $bulk = new Bulk($this->createBulkWriteOptions()); $insertedIds = []; foreach ($this->operations as $i => $operation) { @@ -388,18 +329,35 @@ public function execute(Server $server) } } - $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createOptions()); + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions()); return new BulkWriteResult($writeResult, $insertedIds); } + /** + * Create options for constructing the bulk write. + * + * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @return array + */ + private function createBulkWriteOptions() + { + $options = ['ordered' => $this->options['ordered']]; + + if (isset($this->options['bypassDocumentValidation'])) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + return $options; + } + /** * Create options for executing the bulk write. * * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ - private function createOptions() + private function createExecuteOptions() { $options = []; diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 307dc96be..f0a0983f4 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -33,7 +33,6 @@ use function is_integer; use function is_object; use function is_string; -use function MongoDB\server_supports_feature; /** * Operation for the count command. @@ -44,12 +43,6 @@ */ class Count implements Executable, Explainable { - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForReadConcern = 4; - /** @var string */ private $databaseName; @@ -69,9 +62,6 @@ class Count implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -83,15 +73,10 @@ class Count implements Executable, Explainable * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * skip (integer): The number of documents to skip before returning the * documents. * @@ -156,19 +141,11 @@ public function __construct($databaseName, $collectionName, $filter = [], array * @param Server $server * @return integer * @throws UnexpectedValueException if the command response was malformed - * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws UnsupportedException if read concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) { - throw UnsupportedException::readConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['readConcern'])) { throw UnsupportedException::readConcernNotSupportedInTransaction(); diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index 7591cd08b..df6be9f28 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -65,9 +65,6 @@ class CountDocuments implements Executable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -79,15 +76,10 @@ class CountDocuments implements Executable * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * skip (integer): The number of documents to skip before returning the * documents. * diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index bb7d55f02..76f5e35f5 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -23,7 +23,6 @@ use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; -use MongoDB\Exception\UnsupportedException; use function current; use function is_array; @@ -31,7 +30,6 @@ use function is_integer; use function is_object; use function is_string; -use function MongoDB\server_supports_feature; use function trigger_error; use const E_USER_DEPRECATED; @@ -48,12 +46,6 @@ class CreateCollection implements Executable public const USE_POWER_OF_2_SIZES = 1; public const NO_PADDING = 2; - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var string */ private $databaseName; @@ -81,9 +73,6 @@ class CreateCollection implements Executable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * expireAfterSeconds: The TTL for documents in time series collections. * * This is not supported for servers versions < 5.0. @@ -104,8 +93,6 @@ class CreateCollection implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * size (integer): The maximum number of bytes for a capped collection. * * * storageEngine (document): Storage engine options. @@ -125,9 +112,6 @@ class CreateCollection implements Executable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * @see http://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb * @see https://docs.mongodb.org/manual/core/document-validation/ * @param string $databaseName Database name @@ -224,19 +208,10 @@ public function __construct($databaseName, $collectionName, array $options = []) * @see Executable::execute() * @param Server $server * @return array|object Command result document - * @throws UnsupportedException if collation or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions()); if (isset($this->options['typeMap'])) { diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php index bf98d48b9..58c2dd6c1 100644 --- a/src/Operation/CreateIndexes.php +++ b/src/Operation/CreateIndexes.php @@ -43,12 +43,6 @@ */ class CreateIndexes implements Executable { - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var integer */ private static $wireVersionForCommitQuorum = 9; @@ -61,9 +55,6 @@ class CreateIndexes implements Executable /** @var array */ private $indexes = []; - /** @var boolean */ - private $isCollationUsed = false; - /** @var array */ private $options = []; @@ -81,13 +72,8 @@ class CreateIndexes implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array[] $indexes List of index specifications @@ -111,10 +97,6 @@ public function __construct($databaseName, $collectionName, array $indexes, arra throw InvalidArgumentException::invalidType(sprintf('$index[%d]', $i), $index, 'array'); } - if (isset($index['collation'])) { - $this->isCollationUsed = true; - } - $this->indexes[] = new IndexInput($index); $expectedIndex += 1; @@ -151,19 +133,11 @@ public function __construct($databaseName, $collectionName, array $indexes, arra * @see Executable::execute() * @param Server $server * @return string[] The names of the created indexes - * @throws UnsupportedException if collation or write concern is used and unsupported + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if ($this->isCollationUsed && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php index e94686154..ffe9f3016 100644 --- a/src/Operation/DatabaseCommand.php +++ b/src/Operation/DatabaseCommand.php @@ -57,8 +57,6 @@ class DatabaseCommand implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will be * applied to the returned Cursor (it is not sent to the server). * diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index cf2f45edc..208ceb656 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -43,15 +43,9 @@ */ class Delete implements Executable, Explainable { - /** @var integer */ - private static $wireVersionForCollation = 5; - /** @var integer */ private static $wireVersionForHint = 9; - /** @var int */ - private static $wireVersionForUnsupportedOptionServerSideError = 5; - /** @var string */ private $databaseName; @@ -74,9 +68,6 @@ class Delete implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -86,8 +77,6 @@ class Delete implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name @@ -142,20 +131,11 @@ public function __construct($databaseName, $collectionName, $filter, $limit, arr * @see Executable::execute() * @param Server $server * @return DeleteResult + * @throws UnsupportedException if hint or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - /* Server versions >= 3.4.0 raise errors for unsupported update options. - * For previous versions, the CRUD spec requires a client-side error. */ - if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) { - throw UnsupportedException::hintNotSupported(); - } - /* CRUD spec requires a client-side error when using "hint" with an * unacknowledged write concern on an unsupported server. */ if ( diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index 5ee2dacf7..f5feb0bd9 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -42,9 +42,6 @@ class DeleteMany implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -54,8 +51,6 @@ class DeleteMany implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index cd8d0ff87..d8b35f7dc 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -42,9 +42,6 @@ class DeleteOne implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -54,8 +51,6 @@ class DeleteOne implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 793fd76bf..6d812ce39 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -32,7 +32,6 @@ use function is_integer; use function is_object; use function MongoDB\create_field_path_type_map; -use function MongoDB\server_supports_feature; /** * Operation for the distinct command. @@ -43,12 +42,6 @@ */ class Distinct implements Executable, Explainable { - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForReadConcern = 4; - /** @var string */ private $databaseName; @@ -71,23 +64,15 @@ class Distinct implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. * * @param string $databaseName Database name @@ -145,19 +130,11 @@ public function __construct($databaseName, $collectionName, $fieldName, $filter * @param Server $server * @return mixed[] * @throws UnexpectedValueException if the command response was malformed - * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws UnsupportedException if read concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) { - throw UnsupportedException::readConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['readConcern'])) { throw UnsupportedException::readConcernNotSupportedInTransaction(); diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 23d1805ae..51375022d 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -27,7 +27,6 @@ use function current; use function is_array; -use function MongoDB\server_supports_feature; /** * Operation for the drop command. @@ -42,12 +41,6 @@ class DropCollection implements Executable /** @var integer */ private static $errorCodeNamespaceNotFound = 26; - /** @var string */ - private static $errorMessageNamespaceNotFound = 'ns not found'; - - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var string */ private $databaseName; @@ -64,16 +57,11 @@ class DropCollection implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will be used * for the returned command result document. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array $options Command options @@ -108,15 +96,11 @@ public function __construct($databaseName, $collectionName, array $options = []) * @see Executable::execute() * @param Server $server * @return array|object Command result document - * @throws UnsupportedException if writeConcern is used and unsupported + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); @@ -128,12 +112,9 @@ public function execute(Server $server) $cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions()); } catch (CommandException $e) { /* The server may return an error if the collection does not exist. - * Check for an error code (or message for pre-3.2 servers) and - * return the command reply instead of throwing. */ - if ( - $e->getCode() === self::$errorCodeNamespaceNotFound || - $e->getMessage() === self::$errorMessageNamespaceNotFound - ) { + * Check for an error code and return the command reply instead of + * throwing. */ + if ($e->getCode() === self::$errorCodeNamespaceNotFound) { return $e->getResultDocument(); } diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php index 92a33c2c6..ad96fc869 100644 --- a/src/Operation/DropDatabase.php +++ b/src/Operation/DropDatabase.php @@ -23,11 +23,9 @@ use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; -use MongoDB\Exception\UnsupportedException; use function current; use function is_array; -use function MongoDB\server_supports_feature; /** * Operation for the dropDatabase command. @@ -39,9 +37,6 @@ */ class DropDatabase implements Executable { - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var string */ private $databaseName; @@ -55,16 +50,11 @@ class DropDatabase implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will be used * for the returned command result document. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors @@ -97,15 +87,10 @@ public function __construct($databaseName, array $options = []) * @see Executable::execute() * @param Server $server * @return array|object Command result document - * @throws UnsupportedException if writeConcern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $command = new Command(['dropDatabase' => 1]); $cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions()); diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php index 4543f4003..a8bb5bca2 100644 --- a/src/Operation/DropIndexes.php +++ b/src/Operation/DropIndexes.php @@ -28,7 +28,6 @@ use function current; use function is_array; use function is_integer; -use function MongoDB\server_supports_feature; /** * Operation for the dropIndexes command. @@ -39,9 +38,6 @@ */ class DropIndexes implements Executable { - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var string */ private $databaseName; @@ -64,16 +60,11 @@ class DropIndexes implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will be used * for the returned command result document. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param string $indexName Index name (use "*" to drop all indexes) @@ -120,15 +111,11 @@ public function __construct($databaseName, $collectionName, $indexName, array $o * @see Executable::execute() * @param Server $server * @return array|object Command result document - * @throws UnsupportedException if writeConcern is used and unsupported + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index 1bc117748..1164264fd 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -66,15 +66,10 @@ class EstimatedDocumentCount implements Executable, Explainable * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array $options Command options diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php index e5debe1fe..f9ff3f3df 100644 --- a/src/Operation/Explain.php +++ b/src/Operation/Explain.php @@ -46,12 +46,6 @@ class Explain implements Executable /** @var integer */ private static $wireVersionForAggregate = 7; - /** @var integer */ - private static $wireVersionForDistinct = 4; - - /** @var integer */ - private static $wireVersionForFindAndModify = 4; - /** @var string */ private $databaseName; @@ -114,14 +108,6 @@ public function __construct($databaseName, Explainable $explainable, array $opti */ public function execute(Server $server) { - if ($this->explainable instanceof Distinct && ! server_supports_feature($server, self::$wireVersionForDistinct)) { - throw UnsupportedException::explainNotSupported(); - } - - if ($this->isFindAndModify($this->explainable) && ! server_supports_feature($server, self::$wireVersionForFindAndModify)) { - throw UnsupportedException::explainNotSupported(); - } - if ($this->explainable instanceof Aggregate && ! server_supports_feature($server, self::$wireVersionForAggregate)) { throw UnsupportedException::explainNotSupported(); } diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 0acfa3ae3..29b278204 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -32,7 +32,6 @@ use function is_integer; use function is_object; use function is_string; -use function MongoDB\server_supports_feature; use function trigger_error; use const E_USER_DEPRECATED; @@ -51,15 +50,6 @@ class Find implements Executable, Explainable public const TAILABLE = 2; public const TAILABLE_AWAIT = 3; - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForReadConcern = 4; - - /** @var integer */ - private static $wireVersionForAllowDiskUseServerSideError = 4; - /** @var string */ private $databaseName; @@ -88,9 +78,6 @@ class Find implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * comment (string): Attaches a comment to the query. If "$comment" also * exists in the modifiers document, this option will take precedence. * @@ -136,9 +123,6 @@ class Find implements Executable, Explainable * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * returnKey (boolean): If true, returns only the index keys in the @@ -146,8 +130,6 @@ class Find implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * showRecordId (boolean): Determines whether to return the record * identifier for each document. If true, adds a field $recordId to the * returned documents. @@ -316,23 +298,11 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * @see Executable::execute() * @param Server $server * @return Cursor - * @throws UnsupportedException if collation or read concern is used and unsupported + * @throws UnsupportedException if read concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) { - throw UnsupportedException::readConcernNotSupported(); - } - - if (isset($this->options['allowDiskUse']) && ! server_supports_feature($server, self::$wireVersionForAllowDiskUseServerSideError)) { - throw UnsupportedException::allowDiskUseNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['readConcern'])) { throw UnsupportedException::readConcernNotSupportedInTransaction(); diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 27cf68618..8988e003c 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -48,24 +48,12 @@ */ class FindAndModify implements Executable, Explainable { - /** @var integer */ - private static $wireVersionForArrayFilters = 6; - - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - /** @var integer */ private static $wireVersionForHint = 9; /** @var integer */ private static $wireVersionForUnsupportedOptionServerSideError = 8; - /** @var integer */ - private static $wireVersionForWriteConcern = 4; - /** @var string */ private $databaseName; @@ -83,20 +71,11 @@ class FindAndModify implements Executable, Explainable * * arrayFilters (document array): A set of filters specifying to which * array elements an update should apply. * - * This is not supported for server versions < 3.6 and will result in an - * exception at execution time if used. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * fields (document): Limits the fields to return for the matching * document. * @@ -121,8 +100,6 @@ class FindAndModify implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * sort (document): Determines which document the operation modifies if * the query selects multiple documents. * @@ -137,9 +114,6 @@ class FindAndModify implements Executable, Explainable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array $options Command options @@ -213,6 +187,10 @@ public function __construct($databaseName, $collectionName, array $options) throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (! (isset($options['update']) xor $options['remove'])) { throw new InvalidArgumentException('The "remove" option must be true or an "update" document must be specified, but not both'); } @@ -233,19 +211,11 @@ public function __construct($databaseName, $collectionName, array $options) * @param Server $server * @return array|object|null * @throws UnexpectedValueException if the command response was malformed - * @throws UnsupportedException if array filters, collation, or write concern is used and unsupported + * @throws UnsupportedException if hint or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['arrayFilters']) && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) { - throw UnsupportedException::arrayFiltersNotSupported(); - } - - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - /* Server versions >= 4.2.0 raise errors for unsupported update options. * For previous versions, the CRUD spec requires a client-side error. */ if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) { @@ -261,16 +231,12 @@ public function execute(Server $server) throw UnsupportedException::hintNotSupported(); } - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - $cursor = $server->executeWriteCommand($this->databaseName, new Command($this->createCommandDocument($server)), $this->createOptions()); + $cursor = $server->executeWriteCommand($this->databaseName, new Command($this->createCommandDocument()), $this->createOptions()); if (isset($this->options['typeMap'])) { $cursor->setTypeMap(create_field_path_type_map($this->options['typeMap'], 'value')); @@ -290,16 +256,15 @@ public function execute(Server $server) */ public function getCommandDocument(Server $server) { - return $this->createCommandDocument($server); + return $this->createCommandDocument(); } /** * Create the findAndModify command document. * - * @param Server $server * @return array */ - private function createCommandDocument(Server $server) + private function createCommandDocument() { $cmd = ['findAndModify' => $this->collectionName]; @@ -322,19 +287,12 @@ private function createCommandDocument(Server $server) : (object) $this->options['update']; } - foreach (['arrayFilters', 'hint', 'maxTimeMS'] as $option) { + foreach (['arrayFilters', 'bypassDocumentValidation', 'hint', 'maxTimeMS'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } } - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - return $cmd; } diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index 86cbb0ad2..6fcadf28c 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -44,9 +44,6 @@ class FindOne implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * comment (string): Attaches a comment to the query. If "$comment" also * exists in the modifiers document, this option will take precedence. * @@ -75,9 +72,6 @@ class FindOne implements Executable, Explainable * * * readConcern (MongoDB\Driver\ReadConcern): Read concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * returnKey (boolean): If true, returns only the index keys in the @@ -85,8 +79,6 @@ class FindOne implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * showRecordId (boolean): Determines whether to return the record * identifier for each document. If true, adds a field $recordId to the * returned documents. diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 4042a68dc..3a5ba9b22 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -44,9 +44,6 @@ class FindOneAndDelete implements Executable, Explainable * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -62,8 +59,6 @@ class FindOneAndDelete implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * sort (document): Determines which document the operation modifies if * the query selects multiple documents. * @@ -71,9 +66,6 @@ class FindOneAndDelete implements Executable, Explainable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array|object $filter Query by which to filter documents diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index addb9c22b..5c0147174 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -50,14 +50,8 @@ class FindOneAndReplace implements Executable, Explainable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -79,8 +73,6 @@ class FindOneAndReplace implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * sort (document): Determines which document the operation modifies if * the query selects multiple documents. * @@ -91,9 +83,6 @@ class FindOneAndReplace implements Executable, Explainable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array|object $filter Query by which to filter documents diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index 6d973d380..c742fc7d3 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -54,14 +54,8 @@ class FindOneAndUpdate implements Executable, Explainable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -83,8 +77,6 @@ class FindOneAndUpdate implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * sort (document): Determines which document the operation modifies if * the query selects multiple documents. * @@ -95,9 +87,6 @@ class FindOneAndUpdate implements Executable, Explainable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array|object $filter Query by which to filter documents diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index b9e24549e..9cc869bbf 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -29,7 +29,6 @@ use function is_array; use function is_bool; use function is_object; -use function MongoDB\server_supports_feature; use function sprintf; /** @@ -41,9 +40,6 @@ */ class InsertMany implements Executable { - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - /** @var string */ private $databaseName; @@ -64,17 +60,12 @@ class InsertMany implements Executable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * ordered (boolean): If true, when an insert fails, return without * performing the remaining writes. If false, when a write fails, * continue with the remaining writes, if any. The default is true. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name @@ -121,6 +112,10 @@ public function __construct($databaseName, $collectionName, array $documents, ar throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { unset($options['writeConcern']); } @@ -137,6 +132,7 @@ public function __construct($databaseName, $collectionName, array $documents, ar * @see Executable::execute() * @param Server $server * @return InsertManyResult + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) @@ -146,34 +142,42 @@ public function execute(Server $server) throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - $options = ['ordered' => $this->options['ordered']]; - - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - - $bulk = new Bulk($options); + $bulk = new Bulk($this->createBulkWriteOptions()); $insertedIds = []; foreach ($this->documents as $i => $document) { $insertedIds[$i] = $bulk->insert($document); } - $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createOptions()); + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions()); return new InsertManyResult($writeResult, $insertedIds); } + /** + * Create options for constructing the bulk write. + * + * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @return array + */ + private function createBulkWriteOptions() + { + $options = ['ordered' => $this->options['ordered']]; + + if (isset($this->options['bypassDocumentValidation'])) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + return $options; + } + /** * Create options for executing the bulk write. * * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ - private function createOptions() + private function createExecuteOptions() { $options = []; diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index c7014f56a..f2fba52f7 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -29,7 +29,6 @@ use function is_array; use function is_bool; use function is_object; -use function MongoDB\server_supports_feature; /** * Operation for inserting a single document with the insert command. @@ -40,9 +39,6 @@ */ class InsertOne implements Executable { - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - /** @var string */ private $databaseName; @@ -63,13 +59,8 @@ class InsertOne implements Executable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name @@ -96,6 +87,10 @@ public function __construct($databaseName, $collectionName, $document, array $op throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { unset($options['writeConcern']); } @@ -112,39 +107,48 @@ public function __construct($databaseName, $collectionName, $document, array $op * @see Executable::execute() * @param Server $server * @return InsertOneResult + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - $options = []; - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if (isset($this->options['writeConcern']) && $inTransaction) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - - $bulk = new Bulk($options); + $bulk = new Bulk($this->createBulkWriteOptions()); $insertedId = $bulk->insert($this->document); - $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createOptions()); + $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions()); return new InsertOneResult($writeResult, $insertedId); } + /** + * Create options for constructing the bulk write. + * + * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @return array + */ + private function createBulkWriteOptions() + { + $options = []; + + if (isset($this->options['bypassDocumentValidation'])) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + + return $options; + } + /** * Create options for executing the bulk write. * * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ - private function createOptions() + private function createExecuteOptions() { $options = []; diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index e21af9e3d..678475d89 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -53,8 +53,6 @@ class ListCollectionNames implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param string $databaseName Database name * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php index 898091c98..bdc75f02b 100644 --- a/src/Operation/ListCollections.php +++ b/src/Operation/ListCollections.php @@ -56,8 +56,6 @@ class ListCollections implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param string $databaseName Database name * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php index 531be3403..3104f4b39 100644 --- a/src/Operation/ListDatabaseNames.php +++ b/src/Operation/ListDatabaseNames.php @@ -51,15 +51,11 @@ class ListDatabaseNames implements Executable * * * filter (document): Query by which to filter databases. * - * For servers < 3.6, this option is ignored. - * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ diff --git a/src/Operation/ListDatabases.php b/src/Operation/ListDatabases.php index efe93582f..82da5fad6 100644 --- a/src/Operation/ListDatabases.php +++ b/src/Operation/ListDatabases.php @@ -49,15 +49,11 @@ class ListDatabases implements Executable * * * filter (document): Query by which to filter databases. * - * For servers < 3.6, this option is ignored. - * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index d68187442..34d97b3d7 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -64,8 +64,6 @@ class ListIndexes implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param array $options Command options diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index bc5b91d12..c71ccc34a 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -40,7 +40,6 @@ use function is_string; use function MongoDB\create_field_path_type_map; use function MongoDB\is_mapreduce_output_inline; -use function MongoDB\server_supports_feature; use function trigger_error; use const E_USER_DEPRECATED; @@ -54,18 +53,6 @@ */ class MapReduce implements Executable { - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - - /** @var integer */ - private static $wireVersionForReadConcern = 4; - - /** @var integer */ - private static $wireVersionForWriteConcern = 4; - /** @var string */ private $databaseName; @@ -113,14 +100,8 @@ class MapReduce implements Executable * circumvent document level validation. This only applies when results * are output to a collection. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * finalize (MongoDB\BSON\JavascriptInterface): Follows the reduce method * and modifies the output. * @@ -142,9 +123,6 @@ class MapReduce implements Executable * * readConcern (MongoDB\Driver\ReadConcern): Read concern. This is not * supported when results are returned inline. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * This option is ignored if results are output to a collection. @@ -154,8 +132,6 @@ class MapReduce implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * sort (document): Sorts the input documents. This option is useful for * optimization. For example, specify the sort key to be the same as the * emit key so that there are fewer reduce operations. The sort key must @@ -170,9 +146,6 @@ class MapReduce implements Executable * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. This only * applies when results are output to a collection. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection name * @param JavascriptInterface $map Map function @@ -247,6 +220,10 @@ public function __construct($databaseName, $collectionName, JavascriptInterface throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (isset($options['readConcern']) && $options['readConcern']->isDefault()) { unset($options['readConcern']); } @@ -285,23 +262,11 @@ public function __construct($databaseName, $collectionName, JavascriptInterface * @param Server $server * @return MapReduceResult * @throws UnexpectedValueException if the command response was malformed - * @throws UnsupportedException if collation, read concern, or write concern is used and unsupported + * @throws UnsupportedException if read concern or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - if (isset($this->options['readConcern']) && ! server_supports_feature($server, self::$wireVersionForReadConcern)) { - throw UnsupportedException::readConcernNotSupported(); - } - - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction) { if (isset($this->options['readConcern'])) { @@ -315,7 +280,7 @@ public function execute(Server $server) $hasOutputCollection = ! is_mapreduce_output_inline($this->out); - $command = $this->createCommand($server); + $command = $this->createCommand(); $options = $this->createOptions($hasOutputCollection); /* If the mapReduce operation results in a write, use @@ -363,10 +328,9 @@ private function checkOutDeprecations($out) /** * Create the mapReduce command. * - * @param Server $server * @return Command */ - private function createCommand(Server $server) + private function createCommand() { $cmd = [ 'mapReduce' => $this->collectionName, @@ -375,7 +339,7 @@ private function createCommand(Server $server) 'out' => $this->out, ]; - foreach (['finalize', 'jsMode', 'limit', 'maxTimeMS', 'verbose'] as $option) { + foreach (['bypassDocumentValidation', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'verbose'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } @@ -387,13 +351,6 @@ private function createCommand(Server $server) } } - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - return new Command($cmd); } diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php index 76107b2b3..b38c95baf 100644 --- a/src/Operation/ModifyCollection.php +++ b/src/Operation/ModifyCollection.php @@ -23,11 +23,9 @@ use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; -use MongoDB\Exception\UnsupportedException; use function current; use function is_array; -use function MongoDB\server_supports_feature; /** * Operation for the collMod command. @@ -57,16 +55,11 @@ class ModifyCollection implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will only be * used for the returned command result document. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.2 and will result in an - * exception at execution time if used. - * * @param string $databaseName Database name * @param string $collectionName Collection or view to modify * @param array $collectionOptions Collection or view options to assign @@ -111,10 +104,6 @@ public function __construct($databaseName, $collectionName, array $collectionOpt */ public function execute(Server $server) { - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $cursor = $server->executeWriteCommand($this->databaseName, new Command(['collMod' => $this->collectionName] + $this->collectionOptions), $this->createOptions()); if (isset($this->options['typeMap'])) { diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php index e7be59c09..82ac33c2c 100644 --- a/src/Operation/RenameCollection.php +++ b/src/Operation/RenameCollection.php @@ -27,7 +27,6 @@ use function current; use function is_array; use function is_bool; -use function MongoDB\server_supports_feature; /** * Operation for the renameCollection command. @@ -39,9 +38,6 @@ */ class RenameCollection implements Executable { - /** @var integer */ - private static $wireVersionForWriteConcern = 5; - /** @var string */ private $fromNamespace; @@ -58,16 +54,11 @@ class RenameCollection implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * typeMap (array): Type map for BSON deserialization. This will be used * for the returned command result document. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * dropTarget (boolean): If true, MongoDB will drop the target before * renaming the collection. * @@ -111,15 +102,11 @@ public function __construct(string $fromDatabaseName, string $fromCollectionName * @see Executable::execute() * @param Server $server * @return array|object Command result document - * @throws UnsupportedException if writeConcern is used and unsupported + * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['writeConcern']) && ! server_supports_feature($server, self::$wireVersionForWriteConcern)) { - throw UnsupportedException::writeConcernNotSupported(); - } - $inTransaction = isset($this->options['session']) && $this->options['session']->isInTransaction(); if ($inTransaction && isset($this->options['writeConcern'])) { throw UnsupportedException::writeConcernNotSupportedInTransaction(); diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index 98c75c0a5..c0eef91f9 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -48,14 +48,8 @@ class ReplaceOne implements Executable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -65,8 +59,6 @@ class ReplaceOne implements Executable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 52164db17..09292b9d5 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -46,21 +46,9 @@ */ class Update implements Executable, Explainable { - /** @var integer */ - private static $wireVersionForArrayFilters = 6; - - /** @var integer */ - private static $wireVersionForCollation = 5; - - /** @var integer */ - private static $wireVersionForDocumentLevelValidation = 4; - /** @var integer */ private static $wireVersionForHint = 8; - /** @var integer */ - private static $wireVersionForUnsupportedOptionServerSideError = 5; - /** @var string */ private $databaseName; @@ -84,20 +72,11 @@ class Update implements Executable, Explainable * * arrayFilters (document array): A set of filters specifying to which * array elements an update should apply. * - * This is not supported for server versions < 3.6 and will result in an - * exception at execution time if used. - * * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -111,8 +90,6 @@ class Update implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * @@ -177,6 +154,10 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { + unset($options['bypassDocumentValidation']); + } + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { unset($options['writeConcern']); } @@ -194,25 +175,11 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar * @see Executable::execute() * @param Server $server * @return UpdateResult - * @throws UnsupportedException if array filters or collation is used and unsupported + * @throws UnsupportedException if hint or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) { - if (isset($this->options['arrayFilters']) && ! server_supports_feature($server, self::$wireVersionForArrayFilters)) { - throw UnsupportedException::arrayFiltersNotSupported(); - } - - if (isset($this->options['collation']) && ! server_supports_feature($server, self::$wireVersionForCollation)) { - throw UnsupportedException::collationNotSupported(); - } - - /* Server versions >= 3.4.0 raise errors for unsupported update options. - * For previous versions, the CRUD spec requires a client-side error. */ - if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) { - throw UnsupportedException::hintNotSupported(); - } - /* CRUD spec requires a client-side error when using "hint" with an * unacknowledged write concern on an unsupported server. */ if ( @@ -227,16 +194,7 @@ public function execute(Server $server) throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - $bulkOptions = []; - - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $bulkOptions['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; - } - - $bulk = new Bulk($bulkOptions); + $bulk = new Bulk($this->createBulkWriteOptions()); $bulk->update($this->filter, $this->update, $this->createUpdateOptions()); $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions()); @@ -255,18 +213,32 @@ public function getCommandDocument(Server $server) { $cmd = ['update' => $this->collectionName, 'updates' => [['q' => $this->filter, 'u' => $this->update] + $this->createUpdateOptions()]]; + if (isset($this->options['bypassDocumentValidation'])) { + $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + } + if (isset($this->options['writeConcern'])) { $cmd['writeConcern'] = $this->options['writeConcern']; } - if ( - ! empty($this->options['bypassDocumentValidation']) && - server_supports_feature($server, self::$wireVersionForDocumentLevelValidation) - ) { - $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + return $cmd; + } + + /** + * Create options for constructing the bulk write. + * + * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @return array + */ + private function createBulkWriteOptions() + { + $options = []; + + if (isset($this->options['bypassDocumentValidation'])) { + $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; } - return $cmd; + return $options; } /** diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index 7a5c43581..58f23e972 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -48,20 +48,11 @@ class UpdateMany implements Executable, Explainable * * arrayFilters (document array): A set of filters specifying to which * array elements an update should apply. * - * This is not supported for server versions < 3.6 and will result in an$ - * exception at execution time if used. - * * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -71,8 +62,6 @@ class UpdateMany implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index 2953eb545..f5f13d86f 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -48,20 +48,11 @@ class UpdateOne implements Executable, Explainable * * arrayFilters (document array): A set of filters specifying to which * array elements an update should apply. * - * This is not supported for server versions < 3.6 and will result in an$ - * exception at execution time if used. - * * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * - * For servers < 3.2, this option is ignored as document level validation - * is not available. - * * * collation (document): Collation specification. * - * This is not supported for server versions < 3.4 and will result in an - * exception at execution time if used. - * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -71,8 +62,6 @@ class UpdateOne implements Executable, Explainable * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 0c8c2d9cd..a0a315677 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -132,8 +132,6 @@ class Watch implements Executable, /* @internal */ CommandSubscriber * * * session (MongoDB\Driver\Session): Client session. * - * Sessions are not supported for server versions < 3.6. - * * * startAfter (document): Specifies the logical starting point for the * new change stream. Unlike "resumeAfter", this option can be used with * a resume token from an "invalidate" event. diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index 213b5922a..a51b90d60 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -12,7 +12,6 @@ use function call_user_func; use function is_callable; use function sprintf; -use function version_compare; /** * Functional tests for the Client class. @@ -122,10 +121,6 @@ private function assertDatabaseExists(string $databaseName, ?callable $callback public function testStartSession(): void { - if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { - $this->markTestSkipped('startSession() is only supported on FCV 3.6 or higher'); - } - $this->assertInstanceOf(Session::class, $this->client->startSession()); } } diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index 2c5383116..fad3da65f 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -147,10 +147,6 @@ public function testAggregateWithinTransaction(): void public function testCreateIndexSplitsCommandOptions(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $this->collection->createIndex( diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 28d914b90..9b8206299 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1135,10 +1135,6 @@ public function testAggregation_example_3(): void public function testAggregation_example_4(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('$lookup does not support "let" option'); - } - $db = new Database($this->manager, $this->getDatabaseName()); // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index b296f3b8e..b81cd3241 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -294,9 +294,7 @@ public function configureFailPoint($command, ?Server $server = null): void */ protected function createCollection(array $options = []): void { - if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { - $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; - } + $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; $operation = new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), $options); $operation->execute($this->getPrimaryServer()); @@ -313,9 +311,7 @@ protected function createCollection(array $options = []): void */ protected function dropCollection(array $options = []): void { - if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { - $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; - } + $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName(), $options); $operation->execute($this->getPrimaryServer()); @@ -327,10 +323,6 @@ protected function getFeatureCompatibilityVersion(?ReadPreference $readPreferenc return $this->getServerVersion($readPreference); } - if (version_compare($this->getServerVersion(), '3.4.0', '<')) { - return $this->getServerVersion($readPreference); - } - $cursor = $this->manager->executeCommand( 'admin', new Command(['getParameter' => 1, 'featureCompatibilityVersion' => 1]), @@ -340,16 +332,10 @@ protected function getFeatureCompatibilityVersion(?ReadPreference $readPreferenc $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); $document = current($cursor->toArray()); - // MongoDB 3.6: featureCompatibilityVersion is an embedded document if (isset($document['featureCompatibilityVersion']['version']) && is_string($document['featureCompatibilityVersion']['version'])) { return $document['featureCompatibilityVersion']['version']; } - // MongoDB 3.4: featureCompatibilityVersion is a string - if (isset($document['featureCompatibilityVersion']) && is_string($document['featureCompatibilityVersion'])) { - return $document['featureCompatibilityVersion']; - } - throw new UnexpectedValueException('Could not determine featureCompatibilityVersion'); } @@ -463,10 +449,6 @@ protected function skipIfChangeStreamIsNotSupported(): void switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_MONGOS: case Server::TYPE_LOAD_BALANCER: - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('$changeStream is only supported on MongoDB 3.6 or higher'); - } - if (! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('$changeStream is only supported with replicasets'); } @@ -474,10 +456,6 @@ protected function skipIfChangeStreamIsNotSupported(): void break; case Server::TYPE_RS_PRIMARY: - if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { - $this->markTestSkipped('$changeStream is only supported on FCV 3.6 or higher'); - } - break; default: @@ -490,10 +468,6 @@ protected function skipIfCausalConsistencyIsNotSupported(): void switch ($this->getPrimaryServer()->getType()) { case Server::TYPE_MONGOS: case Server::TYPE_LOAD_BALANCER: - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Causal Consistency is only supported on MongoDB 3.6 or higher'); - } - if (! $this->isShardedClusterUsingReplicasets()) { $this->markTestSkipped('Causal Consistency is only supported with replicasets'); } @@ -501,10 +475,6 @@ protected function skipIfCausalConsistencyIsNotSupported(): void break; case Server::TYPE_RS_PRIMARY: - if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { - $this->markTestSkipped('Causal Consistency is only supported on FCV 3.6 or higher'); - } - if ($this->getServerStorageEngine() !== 'wiredTiger') { $this->markTestSkipped('Causal Consistency requires WiredTiger storage engine'); } diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php index 4eb5a4125..f9c437eac 100644 --- a/tests/Model/IndexInfoFunctionalTest.php +++ b/tests/Model/IndexInfoFunctionalTest.php @@ -5,8 +5,6 @@ use MongoDB\Collection; use MongoDB\Tests\FunctionalTestCase; -use function version_compare; - class IndexInfoFunctionalTest extends FunctionalTestCase { /** @var Collection */ @@ -43,8 +41,8 @@ public function testIs2dSphere(): void $this->assertEquals($indexName, $index->getName()); $this->assertTrue($index->is2dSphere()); - $expectedVersion = version_compare($this->getServerVersion(), '3.2.0', '<') ? 2 : 3; - $this->assertEquals($expectedVersion, $index['2dsphereIndexVersion']); + // MongoDB 3.2+ reports index version 3 + $this->assertEquals(3, $index['2dsphereIndexVersion']); } /** @@ -82,8 +80,8 @@ public function testIsText(): void $this->assertEquals('english', $index['default_language']); $this->assertEquals('language', $index['language_override']); - $expectedVersion = version_compare($this->getServerVersion(), '3.2.0', '<') ? 2 : 3; - $this->assertEquals($expectedVersion, $index['textIndexVersion']); + // MongoDB 3.2+ reports index version 3 + $this->assertEquals(3, $index['textIndexVersion']); $this->assertSameDocument(['x' => 1], $index['weights']); } diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php index 40a70f674..d300fd57b 100644 --- a/tests/Operation/AggregateFunctionalTest.php +++ b/tests/Operation/AggregateFunctionalTest.php @@ -2,7 +2,6 @@ namespace MongoDB\Tests\Operation; -use ArrayIterator; use MongoDB\Collection; use MongoDB\Driver\BulkWrite; use MongoDB\Driver\Exception\RuntimeException; @@ -14,7 +13,6 @@ use function current; use function iterator_to_array; -use function version_compare; class AggregateFunctionalTest extends FunctionalTestCase { @@ -60,10 +58,6 @@ function (array $event): void { public function testCurrentOpCommand(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('$currentOp is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Aggregate( @@ -146,10 +140,6 @@ public function testUnrecognizedPipelineState(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Aggregate( @@ -182,26 +172,6 @@ public function testTypeMapOption(?array $typeMap, array $expectedDocuments): vo $this->assertEquals($expectedDocuments, $results); } - /** - * @dataProvider provideTypeMapOptionsAndExpectedDocuments - */ - public function testTypeMapOptionWithoutCursor(?array $typeMap, array $expectedDocuments): void - { - if (version_compare($this->getServerVersion(), '3.6.0', '>=')) { - $this->markTestSkipped('Aggregations with useCursor == false are not supported'); - } - - $this->createFixtures(3); - - $pipeline = [['$match' => ['_id' => ['$ne' => 2]]]]; - - $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), $pipeline, ['typeMap' => $typeMap, 'useCursor' => false]); - $results = $operation->execute($this->getPrimaryServer()); - - $this->assertInstanceOf(ArrayIterator::class, $results); - $this->assertEquals($expectedDocuments, iterator_to_array($results)); - } - public function testExplainOption(): void { $this->createFixtures(3); @@ -222,10 +192,6 @@ public function testExplainOption(): void public function testExplainOptionWithWriteConcern(): void { - if (version_compare($this->getServerVersion(), '3.4.0', '<')) { - $this->markTestSkipped('The writeConcern option is not supported'); - } - $this->createFixtures(3); $pipeline = [['$match' => ['_id' => ['$ne' => 2]]], ['$out' => $this->getCollectionName() . '.output']]; @@ -258,10 +224,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Aggregate( @@ -282,10 +244,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Aggregate( diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php index ad0f28425..dd0a18eaf 100644 --- a/tests/Operation/BulkWriteFunctionalTest.php +++ b/tests/Operation/BulkWriteFunctionalTest.php @@ -225,10 +225,6 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedIds(BulkWriteResul public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new BulkWrite( @@ -248,10 +244,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new BulkWrite( @@ -272,10 +264,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new BulkWrite( diff --git a/tests/Operation/CountFunctionalTest.php b/tests/Operation/CountFunctionalTest.php index e3ff17a85..550dcbe00 100644 --- a/tests/Operation/CountFunctionalTest.php +++ b/tests/Operation/CountFunctionalTest.php @@ -7,8 +7,6 @@ use MongoDB\Operation\InsertMany; use MongoDB\Tests\CommandObserver; -use function version_compare; - class CountFunctionalTest extends FunctionalTestCase { public function testDefaultReadConcernIsOmitted(): void @@ -50,12 +48,8 @@ public function testHintOption(): void 'sparse_x', ]; - /* Per SERVER-22041, the count command in server versions before 3.3.2 - * may ignore the hint option if its query predicate is empty. */ - $filter = ['_id' => ['$exists' => true]]; - foreach ($hintsUsingSparseIndex as $hint) { - $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), $filter, ['hint' => $hint]); + $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]); $this->assertSame(2, $operation->execute($this->getPrimaryServer())); } @@ -66,17 +60,13 @@ public function testHintOption(): void ]; foreach ($hintsNotUsingSparseIndex as $hint) { - $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), $filter, ['hint' => $hint]); + $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), [], ['hint' => $hint]); $this->assertSame(3, $operation->execute($this->getPrimaryServer())); } } public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Count( diff --git a/tests/Operation/CreateCollectionFunctionalTest.php b/tests/Operation/CreateCollectionFunctionalTest.php index 7e79969b9..aa9d9e592 100644 --- a/tests/Operation/CreateCollectionFunctionalTest.php +++ b/tests/Operation/CreateCollectionFunctionalTest.php @@ -5,8 +5,6 @@ use MongoDB\Operation\CreateCollection; use MongoDB\Tests\CommandObserver; -use function version_compare; - class CreateCollectionFunctionalTest extends FunctionalTestCase { public function testDefaultWriteConcernIsOmitted(): void @@ -29,10 +27,6 @@ function (array $event): void { public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new CreateCollection( diff --git a/tests/Operation/CreateIndexesFunctionalTest.php b/tests/Operation/CreateIndexesFunctionalTest.php index 921a14aa5..8bc79d87a 100644 --- a/tests/Operation/CreateIndexesFunctionalTest.php +++ b/tests/Operation/CreateIndexesFunctionalTest.php @@ -153,10 +153,6 @@ function (array $event): void { public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new CreateIndexes( diff --git a/tests/Operation/DatabaseCommandFunctionalTest.php b/tests/Operation/DatabaseCommandFunctionalTest.php index ee3251361..eee2f2bd2 100644 --- a/tests/Operation/DatabaseCommandFunctionalTest.php +++ b/tests/Operation/DatabaseCommandFunctionalTest.php @@ -5,16 +5,10 @@ use MongoDB\Operation\DatabaseCommand; use MongoDB\Tests\CommandObserver; -use function version_compare; - class DatabaseCommandFunctionalTest extends FunctionalTestCase { public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new DatabaseCommand( diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php index 3b0058ed1..3bfd4c79f 100644 --- a/tests/Operation/DeleteFunctionalTest.php +++ b/tests/Operation/DeleteFunctionalTest.php @@ -64,26 +64,6 @@ public function testDeleteMany(): void $this->assertSameDocuments($expected, $this->collection->find()); } - public function testHintOptionUnsupportedClientSideError(): void - { - if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { - $this->markTestSkipped('server reports error for unsupported delete options'); - } - - $operation = new Delete( - $this->getDatabaseName(), - $this->getCollectionName(), - [], - 0, - ['hint' => '_id_'] - ); - - $this->expectException(UnsupportedException::class); - $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); - - $operation->execute($this->getPrimaryServer()); - } - public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void { if (version_compare($this->getServerVersion(), '4.4.0', '>=')) { @@ -106,10 +86,6 @@ public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSide public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Delete( diff --git a/tests/Operation/DistinctFunctionalTest.php b/tests/Operation/DistinctFunctionalTest.php index b329479ce..8c02b80a0 100644 --- a/tests/Operation/DistinctFunctionalTest.php +++ b/tests/Operation/DistinctFunctionalTest.php @@ -9,7 +9,6 @@ use function is_scalar; use function json_encode; use function usort; -use function version_compare; class DistinctFunctionalTest extends FunctionalTestCase { @@ -35,10 +34,6 @@ function (array $event): void { public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Distinct( diff --git a/tests/Operation/DropCollectionFunctionalTest.php b/tests/Operation/DropCollectionFunctionalTest.php index 696cfefcf..29cd9ead4 100644 --- a/tests/Operation/DropCollectionFunctionalTest.php +++ b/tests/Operation/DropCollectionFunctionalTest.php @@ -6,8 +6,6 @@ use MongoDB\Operation\InsertOne; use MongoDB\Tests\CommandObserver; -use function version_compare; - class DropCollectionFunctionalTest extends FunctionalTestCase { public function testDefaultWriteConcernIsOmitted(): void @@ -60,10 +58,6 @@ public function testDropNonexistentCollection(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new DropCollection( diff --git a/tests/Operation/DropDatabaseFunctionalTest.php b/tests/Operation/DropDatabaseFunctionalTest.php index 5e504bd3a..2b62c6294 100644 --- a/tests/Operation/DropDatabaseFunctionalTest.php +++ b/tests/Operation/DropDatabaseFunctionalTest.php @@ -9,7 +9,6 @@ use MongoDB\Tests\CommandObserver; use function sprintf; -use function version_compare; class DropDatabaseFunctionalTest extends FunctionalTestCase { @@ -62,10 +61,6 @@ public function testDropNonexistentDatabase(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new DropDatabase( diff --git a/tests/Operation/DropIndexesFunctionalTest.php b/tests/Operation/DropIndexesFunctionalTest.php index a90f387f1..cc5f75ffa 100644 --- a/tests/Operation/DropIndexesFunctionalTest.php +++ b/tests/Operation/DropIndexesFunctionalTest.php @@ -12,7 +12,6 @@ use function call_user_func; use function is_callable; use function sprintf; -use function version_compare; class DropIndexesFunctionalTest extends FunctionalTestCase { @@ -123,10 +122,6 @@ public function testDropByIndexInfo(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => ['x' => 1]]]); $operation->execute($this->getPrimaryServer()); diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php index 9ead7aec1..a639a1d67 100644 --- a/tests/Operation/ExplainFunctionalTest.php +++ b/tests/Operation/ExplainFunctionalTest.php @@ -97,10 +97,6 @@ public function testDeleteOne($verbosity, $executionStatsExpected, $allPlansExec */ public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('Explaining distinct command requires server version >= 3.2'); - } - $operation = new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', []); $explainOperation = new Explain($this->getDatabaseName(), $operation, ['verbosity' => $verbosity, 'typeMap' => ['root' => 'array', 'document' => 'array']]); @@ -114,10 +110,6 @@ public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecu */ public function testFindAndModify($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('Explaining findAndModify command requires server version >= 3.2'); - } - $operation = new FindAndModify($this->getDatabaseName(), $this->getCollectionName(), ['remove' => true]); $explainOperation = new Explain($this->getDatabaseName(), $operation, ['verbosity' => $verbosity, 'typeMap' => ['root' => 'array', 'document' => 'array']]); @@ -143,10 +135,6 @@ public function testFind($verbosity, $executionStatsExpected, $allPlansExecution public function testFindMaxAwait(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('maxAwaitTimeMS option is not supported'); - } - $maxAwaitTimeMS = 100; /* Calculate an approximate pivot to use for time assertions. We will @@ -228,10 +216,6 @@ public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecut */ public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('Explaining findOneAndDelete command requires server version >= 3.2'); - } - $operation = new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), []); $explainOperation = new Explain($this->getDatabaseName(), $operation, ['verbosity' => $verbosity, 'typeMap' => ['root' => 'array', 'document' => 'array']]); @@ -245,10 +229,6 @@ public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPl */ public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('Explaining findOneAndReplace command requires server version >= 3.2'); - } - $operation = new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1.1], ['x' => 5]); $explainOperation = new Explain($this->getDatabaseName(), $operation, ['verbosity' => $verbosity, 'typeMap' => ['root' => 'array', 'document' => 'array']]); @@ -262,10 +242,6 @@ public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allP */ public function testFindOneAndUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('Explaining findOneAndUpdate command requires server version >= 3.2'); - } - $operation = new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], ['$rename' => ['x' => 'y']]); $explainOperation = new Explain($this->getDatabaseName(), $operation, ['verbosity' => $verbosity, 'typeMap' => ['root' => 'array', 'document' => 'array']]); @@ -294,10 +270,6 @@ public function testUpdate($verbosity, $executionStatsExpected, $allPlansExecuti public function testUpdateBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - $this->createFixtures(3); (new CommandObserver())->observe( @@ -325,10 +297,6 @@ function (array $event): void { public function testUpdateBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - $this->createFixtures(3); (new CommandObserver())->observe( diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index 5f9902e51..13f6184fb 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -94,10 +94,6 @@ public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSide public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new FindAndModify( @@ -116,10 +112,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new FindAndModify( @@ -139,10 +131,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new FindAndModify( diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php index 957ec6dc2..e8996f27a 100644 --- a/tests/Operation/FindFunctionalTest.php +++ b/tests/Operation/FindFunctionalTest.php @@ -10,7 +10,6 @@ use MongoDB\Tests\CommandObserver; use function microtime; -use function version_compare; class FindFunctionalTest extends FunctionalTestCase { @@ -86,10 +85,6 @@ public function testHintOption(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Find( @@ -152,10 +147,6 @@ public function provideTypeMapOptionsAndExpectedDocuments() public function testMaxAwaitTimeMS(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('maxAwaitTimeMS option is not supported'); - } - $maxAwaitTimeMS = 100; /* Calculate an approximate pivot to use for time assertions. We will diff --git a/tests/Operation/InsertManyFunctionalTest.php b/tests/Operation/InsertManyFunctionalTest.php index 72418928f..e35905f2d 100644 --- a/tests/Operation/InsertManyFunctionalTest.php +++ b/tests/Operation/InsertManyFunctionalTest.php @@ -11,8 +11,6 @@ use MongoDB\Operation\InsertMany; use MongoDB\Tests\CommandObserver; -use function version_compare; - class InsertManyFunctionalTest extends FunctionalTestCase { /** @var Collection */ @@ -58,10 +56,6 @@ public function testInsertMany(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new InsertMany( @@ -81,10 +75,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new InsertMany( @@ -105,10 +95,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new InsertMany( diff --git a/tests/Operation/InsertOneFunctionalTest.php b/tests/Operation/InsertOneFunctionalTest.php index d0c8f374e..1aa1790b7 100644 --- a/tests/Operation/InsertOneFunctionalTest.php +++ b/tests/Operation/InsertOneFunctionalTest.php @@ -11,8 +11,6 @@ use MongoDB\Operation\InsertOne; use MongoDB\Tests\CommandObserver; -use function version_compare; - class InsertOneFunctionalTest extends FunctionalTestCase { /** @var Collection */ @@ -73,10 +71,6 @@ public function testInsertOneWithGeneratedId(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new InsertOne( @@ -96,10 +90,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new InsertOne( @@ -120,10 +110,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new InsertOne( diff --git a/tests/Operation/ListCollectionNamesFunctionalTest.php b/tests/Operation/ListCollectionNamesFunctionalTest.php index 15f121c64..e72c7789c 100644 --- a/tests/Operation/ListCollectionNamesFunctionalTest.php +++ b/tests/Operation/ListCollectionNamesFunctionalTest.php @@ -7,8 +7,6 @@ use MongoDB\Operation\ListCollectionNames; use MongoDB\Tests\CommandObserver; -use function version_compare; - class ListCollectionNamesFunctionalTest extends FunctionalTestCase { public function testListCollectionNamesForNewlyCreatedDatabase(): void @@ -51,10 +49,6 @@ function (array $event): void { public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new ListCollectionNames( diff --git a/tests/Operation/ListCollectionsFunctionalTest.php b/tests/Operation/ListCollectionsFunctionalTest.php index abe184b25..ec48e7e79 100644 --- a/tests/Operation/ListCollectionsFunctionalTest.php +++ b/tests/Operation/ListCollectionsFunctionalTest.php @@ -9,8 +9,6 @@ use MongoDB\Operation\ListCollections; use MongoDB\Tests\CommandObserver; -use function version_compare; - class ListCollectionsFunctionalTest extends FunctionalTestCase { public function testListCollectionsForNewlyCreatedDatabase(): void @@ -45,10 +43,6 @@ public function testListCollectionsForNewlyCreatedDatabase(): void */ public function testIdIndexAndInfo(): void { - if (version_compare($this->getServerVersion(), '3.4.0', '<')) { - $this->markTestSkipped('idIndex and info are not supported'); - } - $server = $this->getPrimaryServer(); $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); @@ -100,10 +94,6 @@ function (array $event): void { public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new ListCollections( diff --git a/tests/Operation/ListDatabaseNamesFunctionalTest.php b/tests/Operation/ListDatabaseNamesFunctionalTest.php index 81d2e83f0..b0b728a89 100644 --- a/tests/Operation/ListDatabaseNamesFunctionalTest.php +++ b/tests/Operation/ListDatabaseNamesFunctionalTest.php @@ -6,8 +6,6 @@ use MongoDB\Operation\ListDatabaseNames; use MongoDB\Tests\CommandObserver; -use function version_compare; - class ListDatabaseNamesFunctionalTest extends FunctionalTestCase { public function testListDatabaseNames(): void @@ -55,10 +53,6 @@ function (array $event): void { public function testFilterOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('listDatabase command "filter" option is not supported'); - } - $server = $this->getPrimaryServer(); $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); @@ -76,10 +70,6 @@ public function testFilterOption(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new ListDatabaseNames( diff --git a/tests/Operation/ListDatabasesFunctionalTest.php b/tests/Operation/ListDatabasesFunctionalTest.php index a14d913a1..45283ccfb 100644 --- a/tests/Operation/ListDatabasesFunctionalTest.php +++ b/tests/Operation/ListDatabasesFunctionalTest.php @@ -8,8 +8,6 @@ use MongoDB\Operation\ListDatabases; use MongoDB\Tests\CommandObserver; -use function version_compare; - class ListDatabasesFunctionalTest extends FunctionalTestCase { public function testListDatabases(): void @@ -58,10 +56,6 @@ function (array $event): void { public function testFilterOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('listDatabase command "filter" option is not supported'); - } - $server = $this->getPrimaryServer(); $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]); @@ -83,10 +77,6 @@ public function testFilterOption(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new ListDatabases( diff --git a/tests/Operation/ListIndexesFunctionalTest.php b/tests/Operation/ListIndexesFunctionalTest.php index d0522edd9..d2d03bf48 100644 --- a/tests/Operation/ListIndexesFunctionalTest.php +++ b/tests/Operation/ListIndexesFunctionalTest.php @@ -9,8 +9,6 @@ use MongoDB\Operation\ListIndexes; use MongoDB\Tests\CommandObserver; -use function version_compare; - class ListIndexesFunctionalTest extends FunctionalTestCase { public function testListIndexesForNewlyCreatedCollection(): void @@ -49,10 +47,6 @@ public function testListIndexesForNonexistentCollection(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new ListIndexes( diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index 9d36a5b34..204be0906 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -152,10 +152,6 @@ public function testResultDoesNotIncludeTimingWithoutVerboseOption(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - $this->createFixtures(3); (new CommandObserver())->observe( @@ -179,10 +175,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - $this->createFixtures(1); (new CommandObserver())->observe( @@ -207,10 +199,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - $this->createFixtures(1); (new CommandObserver())->observe( diff --git a/tests/Operation/RenameCollectionFunctionalTest.php b/tests/Operation/RenameCollectionFunctionalTest.php index d1fa52e0a..198adc369 100644 --- a/tests/Operation/RenameCollectionFunctionalTest.php +++ b/tests/Operation/RenameCollectionFunctionalTest.php @@ -9,8 +9,6 @@ use MongoDB\Operation\RenameCollection; use MongoDB\Tests\CommandObserver; -use function version_compare; - class RenameCollectionFunctionalTest extends FunctionalTestCase { /** @var integer */ @@ -107,11 +105,8 @@ public function testRenameCollectionExistingTarget(): void $this->expectException(CommandException::class); - /* TODO: mongos returns an inconsistent error code (see: SERVER-60632) - * - * Note: pre-3.2 server versions omit an error code. libmongoc will - * substitute MONGOC_ERROR_QUERY_FAILURE in _mongoc_cmd_check_ok. */ - if (! $this->isShardedCluster() && version_compare($this->getServerVersion(), '3.2.0', '>=')) { + // TODO: mongos returns an inconsistent error code (see: SERVER-60632) + if (! $this->isShardedCluster()) { $this->expectExceptionCode(self::$errorCodeNamespaceExists); } @@ -127,12 +122,7 @@ public function testRenameCollectionExistingTarget(): void public function testRenameNonexistentCollection(): void { $this->expectException(CommandException::class); - - /* Note: pre-3.2 server versions omit an error code. libmongoc will - * substitute MONGOC_ERROR_QUERY_FAILURE in _mongoc_cmd_check_ok */ - if (version_compare($this->getServerVersion(), '3.2.0', '>=')) { - $this->expectExceptionCode(self::$errorCodeNamespaceNotFound); - } + $this->expectExceptionCode(self::$errorCodeNamespaceNotFound); $operation = new RenameCollection( $this->getDatabaseName(), @@ -145,10 +135,6 @@ public function testRenameNonexistentCollection(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $server = $this->getPrimaryServer(); diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php index c9514e1f2..cf7392584 100644 --- a/tests/Operation/UpdateFunctionalTest.php +++ b/tests/Operation/UpdateFunctionalTest.php @@ -28,10 +28,6 @@ public function setUp(): void public function testSessionOption(): void { - if (version_compare($this->getServerVersion(), '3.6.0', '<')) { - $this->markTestSkipped('Sessions are not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Update( @@ -52,10 +48,6 @@ function (array $event): void { public function testBypassDocumentValidationSetWhenTrue(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Update( @@ -77,10 +69,6 @@ function (array $event): void { public function testBypassDocumentValidationUnsetWhenFalse(): void { - if (version_compare($this->getServerVersion(), '3.2.0', '<')) { - $this->markTestSkipped('bypassDocumentValidation is not supported'); - } - (new CommandObserver())->observe( function (): void { $operation = new Update( @@ -99,26 +87,6 @@ function (array $event): void { ); } - public function testHintOptionUnsupportedClientSideError(): void - { - if (version_compare($this->getServerVersion(), '3.4.0', '>=')) { - $this->markTestSkipped('server reports error for unsupported update options'); - } - - $operation = new Update( - $this->getDatabaseName(), - $this->getCollectionName(), - ['_id' => 1], - ['$inc' => ['x' => 1]], - ['hint' => '_id_'] - ); - - $this->expectException(UnsupportedException::class); - $this->expectExceptionMessage('Hint is not supported by the server executing this operation'); - - $operation->execute($this->getPrimaryServer()); - } - public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void { if (version_compare($this->getServerVersion(), '4.2.0', '>=')) { diff --git a/tests/UnifiedSpecTests/Constraint/MatchesTest.php b/tests/UnifiedSpecTests/Constraint/MatchesTest.php index c182b2ece..8f0adfd0f 100644 --- a/tests/UnifiedSpecTests/Constraint/MatchesTest.php +++ b/tests/UnifiedSpecTests/Constraint/MatchesTest.php @@ -10,7 +10,6 @@ use function hex2bin; use function preg_quote; -use function version_compare; class MatchesTest extends FunctionalTestCase { @@ -122,10 +121,6 @@ public function testOperatorUnsetOrMatches(): void public function testOperatorSessionLsid(): void { - if (version_compare($this->getFeatureCompatibilityVersion(), '3.6', '<')) { - $this->markTestSkipped('startSession() is only supported on FCV 3.6 or higher'); - } - $session = $this->manager->startSession(); $entityMap = new EntityMap(); From e4a7594ac4b31635fa77455c4038a7013024ba28 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 23 Mar 2022 16:18:39 -0400 Subject: [PATCH 116/321] Update CI configs for ext-mongodb 1.13.0 (#902) --- .evergreen/config.yml | 16 +++++----------- .github/workflows/coding-standards.yml | 2 +- .github/workflows/tests.yml | 8 ++++---- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index b15f1b713..9ed418e1e 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -591,22 +591,16 @@ axes: - id: driver-versions display_name: Driver Version values: - # TODO: Update to "1.13.0" once PHPC 1.13.0 is released - id: "oldest-supported" - # display_name: "1.13.0" - display_name: "1.13-dev (master)" + display_name: "1.13.0" variables: - # EXTENSION_VERSION: "1.13.0" - EXTENSION_BRANCH: "master" - # TODO: Update to "1.13.x"/"stable" once PHPC 1.13.0 is released + EXTENSION_VERSION: "1.13.0" - id: "latest-stable" - # display_name: "1.13.x" - display_name: "1.13-dev (master)" + display_name: "1.13.x" variables: - # EXTENSION_VERSION: "stable" - EXTENSION_BRANCH: "master" + EXTENSION_VERSION: "stable" - id: "latest-dev" - display_name: "1.13-dev (master)" + display_name: "1.14-dev (master)" variables: EXTENSION_BRANCH: "master" diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 27f53b834..0a584a558 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -20,7 +20,7 @@ jobs: php-version: - "7.4" driver-version: - - "mongodb/mongo-php-driver@master" + - "stable" steps: - name: "Checkout" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dae42b290..dc6580c4f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,24 +27,24 @@ jobs: mongodb-version: - "4.4" driver-version: - - "mongodb/mongo-php-driver@master" + - "stable" topology: - "server" include: - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "5.0" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "server" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "replica_set" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "mongodb/mongo-php-driver@master" + driver-version: "stable" topology: "sharded_cluster" steps: From 22e84ad8ea1c30d95a6d8d83d2d2f64af7e16eb9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 23 Mar 2022 17:47:06 -0400 Subject: [PATCH 117/321] Master is now 1.13-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index edfa98f60..083182b24 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.12.x-dev" + "dev-master": "1.13.x-dev" } } } From 3049b5dba3fd0ef5b95a5f2d12a140a8b6a2a180 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Thu, 24 Mar 2022 17:00:20 +0300 Subject: [PATCH 118/321] PHPLIB-609: Allow CachingIterator to handle Iterators with non-unique keys (#896) * Adding new test for non-unique keys support in CachingIterator. Co-authored-by: Aleksandr Rudo --- src/Model/CachingIterator.php | 18 +++++++++++++---- tests/Model/CachingIteratorTest.php | 31 +++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index f6e16d5cd..3bd474843 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -25,7 +25,6 @@ use function count; use function current; -use function key; use function next; use function reset; @@ -40,6 +39,9 @@ */ class CachingIterator implements Countable, Iterator { + private const FIELD_KEY = 0; + private const FIELD_VALUE = 1; + /** @var array */ private $items = []; @@ -87,7 +89,9 @@ public function count() #[ReturnTypeWillChange] public function current() { - return current($this->items); + $currentItem = current($this->items); + + return $currentItem !== false ? $currentItem[self::FIELD_VALUE] : false; } /** @@ -97,7 +101,9 @@ public function current() #[ReturnTypeWillChange] public function key() { - return key($this->items); + $currentItem = current($this->items); + + return $currentItem !== false ? $currentItem[self::FIELD_KEY] : null; } /** @@ -165,6 +171,10 @@ private function storeCurrentItem() return; } - $this->items[$this->iterator->key()] = $this->iterator->current(); + // Storing a new item in the internal cache + $this->items[] = [ + self::FIELD_KEY => $this->iterator->key(), + self::FIELD_VALUE => $this->iterator->current(), + ]; } } diff --git a/tests/Model/CachingIteratorTest.php b/tests/Model/CachingIteratorTest.php index 1ba09039f..1539db3e3 100644 --- a/tests/Model/CachingIteratorTest.php +++ b/tests/Model/CachingIteratorTest.php @@ -152,6 +152,26 @@ public function rewind(): void $this->assertCount(1, $iterator); } + public function testCountNonUniqueKeys(): void + { + $iterator = new CachingIterator($this->getNonUniqueTraversable([1, 2, 3])); + $this->assertCount(3, $iterator); + } + + public function testIterationNonUniqueKeys(): void + { + $iterator = new CachingIterator($this->getNonUniqueTraversable([1, 2, 3])); + + $expectedItem = 1; + + foreach ($iterator as $key => $item) { + $this->assertSame(0, $key); + $this->assertSame($expectedItem++, $item); + } + + $this->assertFalse($iterator->valid()); + } + private function getTraversable($items) { foreach ($items as $item) { @@ -162,4 +182,15 @@ private function getTraversable($items) } } } + + private function getNonUniqueTraversable($items) + { + foreach ($items as $item) { + if ($item instanceof Exception) { + throw $item; + } else { + yield 0 => $item; + } + } + } } From 2a81aafc96beada8cc58a18381817b34c1497395 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Thu, 24 Mar 2022 17:16:16 +0300 Subject: [PATCH 119/321] PHPLIB-662: Unified test runner should error for unexpected operation arguments (#898) --- tests/UnifiedSpecTests/Operation.php | 8 +++ tests/UnifiedSpecTests/Util.php | 98 ++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index e69ce46c8..939bedd22 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -211,6 +211,7 @@ private function execute() private function executeForChangeStream(ChangeStream $changeStream) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(ChangeStream::class, $this->name, $args); switch ($this->name) { case 'iterateUntilDocumentOrError': @@ -243,6 +244,7 @@ private function executeForChangeStream(ChangeStream $changeStream) private function executeForClient(Client $client) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(Client::class, $this->name, $args); switch ($this->name) { case 'createChangeStream': @@ -268,6 +270,7 @@ private function executeForClient(Client $client) private function executeForCollection(Collection $collection) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(Collection::class, $this->name, $args); switch ($this->name) { case 'aggregate': @@ -479,6 +482,7 @@ private function executeForCollection(Collection $collection) private function executeForCursor(Cursor $cursor) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(Cursor::class, $this->name, $args); switch ($this->name) { case 'close': @@ -526,6 +530,7 @@ private function executeForCursor(Cursor $cursor) private function executeForDatabase(Database $database) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(Database::class, $this->name, $args); switch ($this->name) { case 'aggregate': @@ -587,6 +592,7 @@ private function executeForDatabase(Database $database) private function executeForSession(Session $session) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(Session::class, $this->name, $args); switch ($this->name) { case 'abortTransaction': @@ -627,6 +633,7 @@ private function executeForSession(Session $session) private function executeForBucket(Bucket $bucket) { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(Bucket::class, $this->name, $args); switch ($this->name) { case 'delete': @@ -672,6 +679,7 @@ private function executeForBucket(Bucket $bucket) private function executeForTestRunner() { $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(self::OBJECT_TEST_RUNNER, $this->name, $args); switch ($this->name) { case 'assertCollectionExists': diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 2f2c79693..fd9ca40d4 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -2,9 +2,16 @@ namespace MongoDB\Tests\UnifiedSpecTests; +use MongoDB\ChangeStream; +use MongoDB\Client; +use MongoDB\Collection; +use MongoDB\Database; +use MongoDB\Driver\Cursor; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; +use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; +use MongoDB\GridFS\Bucket; use stdClass; use function array_diff_key; @@ -26,6 +33,92 @@ final class Util { + /** + * Array to fill, which contains the schema of allowed attributes for operations. + */ + private static $args = [ + Operation::OBJECT_TEST_RUNNER => [ + 'assertCollectionExists' => ['databaseName', 'collectionName'], + 'assertCollectionNotExists' => ['databaseName', 'collectionName'], + 'assertIndexExists' => ['databaseName', 'collectionName', 'indexName'], + 'assertIndexNotExists' => ['databaseName', 'collectionName', 'indexName'], + 'assertSameLsidOnLastTwoCommands' => ['client'], + 'assertDifferentLsidOnLastTwoCommands' => ['client'], + 'assertNumberConnectionsCheckedOut' => ['connections'], + 'assertSessionDirty' => ['session'], + 'assertSessionNotDirty' => ['session'], + 'assertSessionPinned' => ['session'], + 'assertSessionTransactionState' => ['session', 'state'], + 'assertSessionUnpinned' => ['session'], + 'failPoint' => ['client', 'failPoint'], + 'targetedFailPoint' => ['session', 'failPoint'], + 'loop' => ['operations', 'storeErrorsAsEntity', 'storeFailuresAsEntity', 'storeSuccessesAsEntity', 'storeIterationsAsEntity'], + ], + Client::class => [ + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'listDatabaseNames' => ['authorizedDatabases', 'filter', 'maxTimeMS', 'session'], + 'listDatabases' => ['authorizedDatabases', 'filter', 'maxTimeMS', 'session'], + ], + Database::class => [ + 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator'], + 'dropCollection' => ['collection', 'session'], + 'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], + 'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], + // Note: commandName is not used by PHP + 'runCommand' => ['command', 'session', 'commandName'], + ], + Collection::class => [ + 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], + 'bulkWrite' => ['requests', 'session', 'ordered', 'bypassDocumentValidation'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session'], + 'dropIndex' => ['name', 'session', 'maxTimeMS'], + 'count' => ['filter', 'session', 'collation', 'hint', 'limit', 'maxTimeMS', 'skip'], + 'countDocuments' => ['filter', 'session', 'limit', 'skip', 'collation', 'hint', 'maxTimeMS'], + 'estimatedDocumentCount' => ['session', 'maxTimeMS'], + 'deleteMany' => ['filter', 'session', 'collation', 'hint'], + 'deleteOne' => ['filter', 'session', 'collation', 'hint'], + 'findOneAndDelete' => ['filter', 'session', 'projection', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'sort', 'update', 'upsert'], + 'distinct' => ['fieldName', 'filter', 'session', 'collation', 'maxTimeMS'], + 'drop' => ['session'], + 'find' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'findOne' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'findOneAndReplace' => ['returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort'], + 'replaceOne' => ['filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], + 'findOneAndUpdate' => ['returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort'], + 'updateMany' => ['filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], + 'updateOne' => ['filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], + 'insertMany' => ['options', 'documents', 'session', 'ordered', 'bypassDocumentValidation'], + 'insertOne' => ['document', 'session', 'bypassDocumentValidation'], + 'listIndexes' => ['session', 'maxTimeMS'], + 'mapReduce' => ['map', 'reduce', 'out', 'session', 'bypassDocumentValidation', 'collation', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'query', 'scope', 'sort', 'verbose'], + ], + ChangeStream::class => [ + 'iterateUntilDocumentOrError' => [], + ], + Cursor::class => [ + 'close' => [], + 'iterateUntilDocumentOrError' => [], + ], + Session::class => [ + 'abortTransaction' => [], + 'commitTransaction' => [], + 'endSession' => [], + 'startTransaction' => ['maxCommitTimeMS', 'readConcern', 'readPreference', 'writeConcern'], + 'withTransaction' => ['callback', 'maxCommitTimeMS', 'readConcern', 'readPreference', 'writeConcern'], + ], + Bucket::class => [ + 'delete' => ['id'], + 'downloadByName' => ['filename', 'revision'], + 'download' => ['id'], + 'uploadWithId' => ['id', 'filename', 'source', 'chunkSizeBytes', 'disableMD5', 'contentType', 'metadata'], + 'upload' => ['filename', 'source', 'chunkSizeBytes', 'disableMD5', 'contentType', 'metadata'], + ], + ]; + public static function assertHasOnlyKeys($arrayOrObject, array $keys): void { assertThat($arrayOrObject, logicalOr(isType('array'), isInstanceOf(stdClass::class))); @@ -33,6 +126,11 @@ public static function assertHasOnlyKeys($arrayOrObject, array $keys): void assertEmpty($diff, 'Unsupported keys: ' . implode(',', array_keys($diff))); } + public static function assertArgumentsBySchema(string $executingObjectName, string $operation, array $args): void + { + self::assertHasOnlyKeys($args, self::$args[$executingObjectName][$operation]); + } + public static function createReadConcern(stdClass $o): ReadConcern { self::assertHasOnlyKeys($o, ['level']); From 5ef7251a1351ad5a874a30e016c1b020f586109a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 30 Mar 2022 09:58:27 -0400 Subject: [PATCH 120/321] PHPLIB-789: Snapshot query examples (#900) Includes work-arounds for SnapshotUnavailable(246) errors on replica sets and sharded clusters. Update spec links for StaleDbVersion workaround --- tests/DocumentationExamplesTest.php | 154 +++++++++++++++++++ tests/SpecTests/TransactionsSpecTest.php | 2 +- tests/UnifiedSpecTests/UnifiedTestRunner.php | 2 +- 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 9b8206299..b7fb8ce4d 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -4,13 +4,16 @@ use MongoDB\BSON\ObjectId; use MongoDB\BSON\UTCDateTime; +use MongoDB\Collection; use MongoDB\Database; use MongoDB\Driver\Cursor; +use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; use function in_array; +use function microtime; use function ob_end_clean; use function ob_start; use function var_dump; @@ -1571,6 +1574,119 @@ public function testCausalConsistency(): void ob_end_clean(); } + public function testSnapshotQueries(): void + { + if (version_compare($this->getServerVersion(), '5.0.0', '<')) { + $this->markTestSkipped('Snapshot queries outside of transactions are not supported'); + } + + if (! ($this->isReplicaSet() || $this->isShardedClusterUsingReplicasets())) { + $this->markTestSkipped('Snapshot read concern is only supported with replicasets'); + } + + $client = static::createTestClient(); + + $catsCollection = $client->selectCollection('pets', 'cats'); + $catsCollection->drop(); + $catsCollection->insertMany([ + ['name' => 'Whiskers', 'color' => 'white', 'adoptable' => true], + ['name' => 'Garfield', 'color' => 'orange', 'adoptable' => false], + ]); + + $dogsCollection = $client->selectCollection('pets', 'dogs'); + $dogsCollection->drop(); + $dogsCollection->insertMany([ + ['name' => 'Toto', 'color' => 'black', 'adoptable' => true], + ['name' => 'Milo', 'color' => 'black', 'adoptable' => false], + ['name' => 'Brian', 'color' => 'white', 'adoptable' => true], + ]); + + if ($this->isShardedCluster()) { + $this->preventStaleDbVersionError('pets', 'cats'); + $this->preventStaleDbVersionError('pets', 'dogs'); + } else { + $this->waitForSnapshot('pets', 'cats'); + $this->waitForSnapshot('pets', 'dogs'); + } + + ob_start(); + + // Start Snapshot Query Example 1 + $catsCollection = $client->selectCollection('pets', 'cats'); + $dogsCollection = $client->selectCollection('pets', 'dogs'); + + $session = $client->startSession(['snapshot' => true]); + + $adoptablePetsCount = $catsCollection->aggregate( + [ + ['$match' => ['adoptable' => true]], + ['$count' => 'adoptableCatsCount'], + ], + ['session' => $session] + )->toArray()[0]->adoptableCatsCount; + + $adoptablePetsCount += $dogsCollection->aggregate( + [ + ['$match' => ['adoptable' => true]], + ['$count' => 'adoptableDogsCount'], + ], + ['session' => $session] + )->toArray()[0]->adoptableDogsCount; + + var_dump($adoptablePetsCount); + // End Snapshot Query Example 1 + + ob_end_clean(); + + $this->assertSame(3, $adoptablePetsCount); + + $catsCollection->drop(); + $dogsCollection->drop(); + + $salesCollection = $client->selectCollection('retail', 'sales'); + $salesCollection->drop(); + $salesCollection->insertMany([ + ['shoeType' => 'boot', 'price' => 30, 'saleDate' => new UTCDateTime()], + ]); + + if ($this->isShardedCluster()) { + $this->preventStaleDbVersionError('retail', 'sales'); + } else { + $this->waitForSnapshot('retail', 'sales'); + } + + // Start Snapshot Query Example 2 + $salesCollection = $client->selectCollection('retail', 'sales'); + + $session = $client->startSession(['snapshot' => true]); + + $totalDailySales = $salesCollection->aggregate( + [ + [ + '$match' => [ + '$expr' => [ + '$gt' => ['$saleDate', [ + '$dateSubtract' => [ + 'startDate' => '$$NOW', + 'unit' => 'day', + 'amount' => 1, + ], + ], + ], + ], + ], + ], + ['$count' => 'totalDailySales'], + ], + ['session' => $session] + )->toArray()[0]->totalDailySales; + // End Snapshot Query Example 2 + + $this->assertSame(1, $totalDailySales); + + $salesCollection->drop(); + } + /** * @doesNotPerformAssertions */ @@ -1747,4 +1863,42 @@ private function assertInventoryCount($count): void { $this->assertCollectionCount($this->getDatabaseName() . '.' . $this->getCollectionName(), $count); } + + private function waitForSnapshot(string $databaseName, string $collectionName): void + { + $collection = new Collection($this->manager, $databaseName, $collectionName); + $session = $this->manager->startSession(['snapshot' => true]); + + /* Retry until a snapshot query succeeds or ten seconds elapse, + * whichwever comes first. + * + * TODO: use hrtime() once the library requires PHP 7.3+ */ + $retryUntil = microtime(true) + 10; + + do { + try { + $collection->aggregate( + [['$match' => ['_id' => ['$exists' => true]]]], + ['session' => $session] + ); + + break; + } catch (CommandException $e) { + if ($e->getCode() === 246 /* SnapshotUnavailable */) { + continue; + } + + throw $e; + } + } while (microtime(true) < $retryUntil); + } + + /** + * @see https://jira.mongodb.org/browse/SERVER-39704 + */ + private function preventStaleDbVersionError(string $databaseName, string $collectionName): void + { + $collection = new Collection($this->manager, $databaseName, $collectionName); + $collection->distinct('foo'); + } } diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index d4c40cf76..3a33ca30a 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -353,7 +353,7 @@ private static function killAllSessions(): void * Work around potential error executing distinct on sharded clusters. * * @param array $operations - * @see https://github.com/mongodb/specifications/tree/master/source/transactions/tests#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversionts. + * @see https://github.com/mongodb/specifications/tree/master/source/transactions/tests#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversion */ private function preventStaleDbVersionError(array $operations): void { diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 696268980..def0a53dc 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -442,7 +442,7 @@ private function prepareInitialData(array $initialData): void /** * Work around potential error executing distinct on sharded clusters. * - * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversion + * @see https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst#staledbversion-errors-on-sharded-clusters */ private function preventStaleDbVersionError(array $operations, Context $context): void { From d93532cbd395c1d54f741b6f21a132d69ba2c35f Mon Sep 17 00:00:00 2001 From: Nathan Date: Wed, 30 Mar 2022 09:48:04 -0700 Subject: [PATCH 121/321] DOCSP-20374: Migrate docs.mongodb.com to mongodb.com/docs (#903) Also updates a few broken links Co-authored-by: Jeremy Mikola --- .github/ISSUE_TEMPLATE/bug-report.md | 2 +- .github/ISSUE_TEMPLATE/config.yml | 2 +- CONTRIBUTING.md | 6 ++-- README.md | 10 +++--- ...oDBClient-method-listDatabases-option.yaml | 3 +- ...piargs-MongoDBCollection-common-param.yaml | 2 +- ...atabase-method-listCollections-option.yaml | 2 +- src/ChangeStream.php | 2 +- src/Client.php | 2 +- src/Collection.php | 36 +++++++++---------- src/Command/ListCollections.php | 2 +- src/Command/ListDatabases.php | 2 +- src/MapReduceResult.php | 2 +- src/Model/CollectionInfo.php | 8 ++--- src/Model/CollectionInfoCommandIterator.php | 2 +- src/Model/DatabaseInfo.php | 2 +- src/Model/DatabaseInfoLegacyIterator.php | 2 +- src/Model/IndexInfo.php | 8 ++--- src/Model/IndexInfoIteratorIterator.php | 4 +-- src/Model/IndexInput.php | 2 +- src/Operation/Aggregate.php | 2 +- src/Operation/Count.php | 2 +- src/Operation/CreateCollection.php | 4 +-- src/Operation/CreateIndexes.php | 2 +- src/Operation/Delete.php | 2 +- src/Operation/DeleteMany.php | 2 +- src/Operation/DeleteOne.php | 2 +- src/Operation/Distinct.php | 2 +- src/Operation/DropCollection.php | 2 +- src/Operation/DropDatabase.php | 2 +- src/Operation/DropIndexes.php | 2 +- src/Operation/EstimatedDocumentCount.php | 2 +- src/Operation/Explain.php | 2 +- src/Operation/Find.php | 4 +-- src/Operation/FindAndModify.php | 2 +- src/Operation/FindOne.php | 4 +-- src/Operation/FindOneAndDelete.php | 2 +- src/Operation/FindOneAndReplace.php | 2 +- src/Operation/FindOneAndUpdate.php | 2 +- src/Operation/InsertMany.php | 2 +- src/Operation/InsertOne.php | 2 +- src/Operation/ListCollectionNames.php | 2 +- src/Operation/ListCollections.php | 2 +- src/Operation/ListDatabaseNames.php | 2 +- src/Operation/ListDatabases.php | 2 +- src/Operation/ListIndexes.php | 2 +- src/Operation/MapReduce.php | 2 +- src/Operation/ModifyCollection.php | 2 +- src/Operation/RenameCollection.php | 2 +- src/Operation/ReplaceOne.php | 2 +- src/Operation/Update.php | 2 +- src/Operation/UpdateMany.php | 2 +- src/Operation/UpdateOne.php | 2 +- src/Operation/Watch.php | 2 +- src/functions.php | 4 +-- tests/Collection/CollectionFunctionalTest.php | 2 +- tests/Database/DatabaseFunctionalTest.php | 2 +- tests/DocumentationExamplesTest.php | 4 +-- 58 files changed, 93 insertions(+), 94 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 888e539ed..996a7c95b 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -16,7 +16,7 @@ If you've identified a security vulnerability in a driver or any other MongoDB project, please create a vulnerability report[^2]. [^1]: https://github.com/mongodb/mongo-php-driver -[^2]: https://docs.mongodb.org/manual/tutorial/create-a-vulnerability-report +[^2]: https://mongodb.com/docs/manual/tutorial/create-a-vulnerability-report --> ### Bug Report diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 4ab6a78f8..e3377e688 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -8,5 +8,5 @@ contact_links: url: https://developer.mongodb.com/community/forums/ about: For questions, discussions, or general technical support, visit the MongoDB Community Forums. The MongoDB Community Forums are a centralized place to connect with other MongoDB users, ask questions, and get answers. - name: Report a Security Vulnerability - url: https://docs.mongodb.org/manual/tutorial/create-a-vulnerability-report + url: https://mongodb.com/docs/manual/tutorial/create-a-vulnerability-report about: If you believe you have discovered a vulnerability in MongoDB products or have experienced a security incident related to MongoDB products, please report the issue to aid in its resolution. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90c56b0ff..a6922de74 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -197,7 +197,7 @@ $JIRA_URL **Documentation** Documentation for this library may be found at: -https://docs.mongodb.com/php-library/ +https://mongodb.com/docs/php-library/current/ **Installation** @@ -231,13 +231,13 @@ New major and minor releases will also require documentation updates to other projects: * Create a DOCSP ticket to add the new version to PHP's server and language - [compatibility tables](https://docs.mongodb.com/drivers/php/#compatibility) + [compatibility tables](https://mongodb.com/docs/drivers/php/#compatibility) in the driver docs portal. See [mongodb/docs-ecosystem#642](https://github.com/mongodb/docs-ecosystem/pull/642) for an example. * Create a DOCSP ticket to update the "current" and "upcoming" navigation links - in the library's [documentation](https://docs.mongodb.com/php-library/). This + in the library's [documentation](https://mongodb.com/docs/php-library/current). This will require updating [mongodb/docs-php-library](https://github.com/mongodb/docs-php-library). diff --git a/README.md b/README.md index 3f48d37a4..8b0fbf3da 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,8 @@ extension may be found in ## Documentation - - https://docs.mongodb.com/php-library/ - - https://docs.mongodb.com/ecosystem/drivers/php/ + - https://mongodb.com/docs/php-library/current + - https://mongodb.com/docs/ecosystem/drivers/php/ ## Installation @@ -33,7 +33,7 @@ root: $ composer require mongodb/mongodb Additional installation instructions may be found in the -[library documentation](https://docs.mongodb.com/php-library/current/tutorial/install-php-library/). +[library documentation](https://mongodb.com/docs/php-library/current/tutorial/install-php-library/). Since this library is a high-level abstraction for the driver, it also requires that the `mongodb` extension be installed: @@ -53,13 +53,13 @@ project in MongoDB's JIRA. Extension-related issues should be reported in the project. For general questions and support requests, please use one of MongoDB's -[Technical Support](https://docs.mongodb.com/manual/support/) channels. +[Technical Support](https://mongodb.com/docs/manual/support/) channels. ### Security Vulnerabilities If you've identified a security vulnerability in a driver or any other MongoDB project, please report it according to the instructions in -[Create a Vulnerability Report](https://docs.mongodb.org/manual/tutorial/create-a-vulnerability-report). +[Create a Vulnerability Report](https://mongodb.com/docs/manual/tutorial/create-a-vulnerability-report). ## Development diff --git a/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml b/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml index b9a9c23e2..fa544cce0 100644 --- a/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml @@ -4,7 +4,7 @@ type: boolean description: | A flag that determines which databases are returned based on the user privileges when access control is enabled. For more information, see the - `listDatabases command documentation `_. + `listDatabases command documentation `_. For servers < 4.0.5, this option is ignored. @@ -36,4 +36,3 @@ source: ref: session post: | .. versionadded:: 1.3 -... diff --git a/docs/includes/apiargs-MongoDBCollection-common-param.yaml b/docs/includes/apiargs-MongoDBCollection-common-param.yaml index 9c032d151..47100d19a 100644 --- a/docs/includes/apiargs-MongoDBCollection-common-param.yaml +++ b/docs/includes/apiargs-MongoDBCollection-common-param.yaml @@ -25,7 +25,7 @@ description: | Specifies the field and value combinations to update and any relevant update operators. ``$update`` uses MongoDB's :method:`update operators `. Starting with MongoDB 4.2, an `aggregation - pipeline `_ + pipeline `_ can be passed as this parameter. interface: phpmethod operation: ~ diff --git a/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml index de05bf339..49f41dacb 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml @@ -4,7 +4,7 @@ type: boolean description: | A flag that determines which collections are returned based on the user privileges when access control is enabled. For more information, see the - `listCollections command documentation `_. + `listCollections command documentation `_. For servers < 4.0, this option is ignored. diff --git a/src/ChangeStream.php b/src/ChangeStream.php index 10abebca7..9cdf73550 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -34,7 +34,7 @@ * * @api * @see \MongoDB\Collection::watch() - * @see http://docs.mongodb.org/manual/reference/command/changeStream/ + * @see https://mongodb.com/docs/manual/reference/method/db.watch/#mongodb-method-db.watch */ class ChangeStream implements Iterator { diff --git a/src/Client.php b/src/Client.php index a1718ae9c..ffb879505 100644 --- a/src/Client.php +++ b/src/Client.php @@ -88,7 +88,7 @@ class Client * * Other options are documented in MongoDB\Driver\Manager::__construct(). * - * @see http://docs.mongodb.org/manual/reference/connection-string/ + * @see http://mongodb.com/docs/manual/reference/connection-string/ * @see http://php.net/manual/en/mongodb-driver-manager.construct.php * @see http://php.net/manual/en/mongodb.persistence.php#mongodb.persistence.typemaps * @param string $uri MongoDB connection string diff --git a/src/Collection.php b/src/Collection.php index d25db7105..33205214f 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -183,7 +183,7 @@ public function __debugInfo() /** * Return the collection namespace (e.g. "db.collection"). * - * @see https://docs.mongodb.org/manual/faq/developers/#faq-dev-namespace + * @see https://mongodb.com/docs/manual/core/databases-and-collections/ * @return string */ public function __toString() @@ -368,8 +368,8 @@ public function createIndex($key, array $options = []) * If the "name" option is unspecified, a name will be generated from the * "key" document. * - * @see http://docs.mongodb.org/manual/reference/command/createIndexes/ - * @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/ + * @see http://mongodb.com/docs/manual/reference/command/createIndexes/ + * @see http://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ * @see CreateIndexes::__construct() for supported command options * @param array[] $indexes List of index specifications * @param array $options Command options @@ -395,7 +395,7 @@ public function createIndexes(array $indexes, array $options = []) * Deletes all documents matching the filter. * * @see DeleteMany::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @see http://mongodb.com/docs/manual/reference/command/delete/ * @param array|object $filter Query by which to delete documents * @param array $options Command options * @return DeleteResult @@ -419,7 +419,7 @@ public function deleteMany($filter, array $options = []) * Deletes at most one document matching the filter. * * @see DeleteOne::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @see http://mongodb.com/docs/manual/reference/command/delete/ * @param array|object $filter Query by which to delete documents * @param array $options Command options * @return DeleteResult @@ -593,7 +593,7 @@ public function estimatedDocumentCount(array $options = []) * Explains explainable commands. * * @see Explain::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/explain/ + * @see http://mongodb.com/docs/manual/reference/command/explain/ * @param Explainable $explainable Command on which to run explain * @param array $options Additional options * @return array|object @@ -622,7 +622,7 @@ public function explain(Explainable $explainable, array $options = []) * Finds documents matching the query. * * @see Find::__construct() for supported options - * @see http://docs.mongodb.org/manual/core/read-operations-introduction/ + * @see https://mongodb.com/docs/manual/crud/#read-operations * @param array|object $filter Query by which to filter documents * @param array $options Additional options * @return Cursor @@ -655,7 +655,7 @@ public function find($filter = [], array $options = []) * Finds a single document matching the query. * * @see FindOne::__construct() for supported options - * @see http://docs.mongodb.org/manual/core/read-operations-introduction/ + * @see https://mongodb.com/docs/manual/crud/#read-operations * @param array|object $filter Query by which to filter documents * @param array $options Additional options * @return array|object|null @@ -690,7 +690,7 @@ public function findOne($filter = [], array $options = []) * The document to return may be null if no document matched the filter. * * @see FindOneAndDelete::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ * @param array|object $filter Query by which to filter documents * @param array $options Command options * @return array|object|null @@ -726,7 +726,7 @@ public function findOneAndDelete($filter, array $options = []) * to return the updated document. * * @see FindOneAndReplace::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ * @param array|object $filter Query by which to filter documents * @param array|object $replacement Replacement document * @param array $options Command options @@ -763,7 +763,7 @@ public function findOneAndReplace($filter, $replacement, array $options = []) * to return the updated document. * * @see FindOneAndReplace::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ * @param array|object $filter Query by which to filter documents * @param array|object $update Update to apply to the matched document * @param array $options Command options @@ -823,7 +823,7 @@ public function getManager() /** * Return the collection namespace. * - * @see https://docs.mongodb.org/manual/reference/glossary/#term-namespace + * @see https://mongodb.com/docs/manual/reference/glossary/#term-namespace * @return string */ public function getNamespace() @@ -877,7 +877,7 @@ public function getWriteConcern() * Inserts multiple documents. * * @see InsertMany::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/insert/ + * @see http://mongodb.com/docs/manual/reference/command/insert/ * @param array[]|object[] $documents The documents to insert * @param array $options Command options * @return InsertManyResult @@ -900,7 +900,7 @@ public function insertMany(array $documents, array $options = []) * Inserts one document. * * @see InsertOne::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/insert/ + * @see http://mongodb.com/docs/manual/reference/command/insert/ * @param array|object $document The document to insert * @param array $options Command options * @return InsertOneResult @@ -940,7 +940,7 @@ public function listIndexes(array $options = []) * Executes a map-reduce aggregation on the collection. * * @see MapReduce::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/mapReduce/ + * @see http://mongodb.com/docs/manual/reference/command/mapReduce/ * @param JavascriptInterface $map Map function * @param JavascriptInterface $reduce Reduce function * @param string|array|object $out Output specification @@ -1025,7 +1025,7 @@ public function rename(string $toCollectionName, ?string $toDatabaseName = null, * Replaces at most one document matching the filter. * * @see ReplaceOne::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ * @param array|object $filter Query by which to filter documents * @param array|object $replacement Replacement document * @param array $options Command options @@ -1050,7 +1050,7 @@ public function replaceOne($filter, $replacement, array $options = []) * Updates all documents matching the filter. * * @see UpdateMany::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ * @param array|object $filter Query by which to filter documents * @param array|object $update Update to apply to the matched documents * @param array $options Command options @@ -1075,7 +1075,7 @@ public function updateMany($filter, $update, array $options = []) * Updates at most one document matching the filter. * * @see UpdateOne::__construct() for supported options - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ * @param array|object $filter Query by which to filter documents * @param array|object $update Update to apply to the matched document * @param array $options Command options diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index 2e2d7372a..b09cc8722 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -34,7 +34,7 @@ * Wrapper for the listCollections command. * * @internal - * @see http://docs.mongodb.org/manual/reference/command/listCollections/ + * @see http://mongodb.com/docs/manual/reference/command/listCollections/ */ class ListCollections implements Executable { diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index 91c793f57..26a5e6de3 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -35,7 +35,7 @@ * Wrapper for the ListDatabases command. * * @internal - * @see http://docs.mongodb.org/manual/reference/command/listDatabases/ + * @see http://mongodb.com/docs/manual/reference/command/listDatabases/ */ class ListDatabases implements Executable { diff --git a/src/MapReduceResult.php b/src/MapReduceResult.php index 577a3dda3..f9cb503a2 100644 --- a/src/MapReduceResult.php +++ b/src/MapReduceResult.php @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::mapReduce() - * @see https://docs.mongodb.com/manual/reference/command/mapReduce/ + * @see https://mongodb.com/docs/manual/reference/command/mapReduce/ */ class MapReduceResult implements IteratorAggregate { diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php index e0d201af5..7efdd8d6e 100644 --- a/src/Model/CollectionInfo.php +++ b/src/Model/CollectionInfo.php @@ -97,7 +97,7 @@ public function getIdIndex(): array /** * Return the "info" property of the server response. * - * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output + * @see https://mongodb.com/docs/manual/reference/command/listCollections/#output * @return array */ public function getInfo(): array @@ -108,7 +108,7 @@ public function getInfo(): array /** * Return the collection name. * - * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output + * @see https://mongodb.com/docs/manual/reference/command/listCollections/#output * @return string */ public function getName() @@ -119,7 +119,7 @@ public function getName() /** * Return the collection options. * - * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output + * @see https://mongodb.com/docs/manual/reference/command/listCollections/#output * @return array */ public function getOptions() @@ -130,7 +130,7 @@ public function getOptions() /** * Return the collection type. * - * @see https://docs.mongodb.com/manual/reference/command/listCollections/#output + * @see https://mongodb.com/docs/manual/reference/command/listCollections/#output * @return string */ public function getType(): string diff --git a/src/Model/CollectionInfoCommandIterator.php b/src/Model/CollectionInfoCommandIterator.php index 4bb32dc12..4324c1338 100644 --- a/src/Model/CollectionInfoCommandIterator.php +++ b/src/Model/CollectionInfoCommandIterator.php @@ -30,7 +30,7 @@ * @internal * @see \MongoDB\Database::listCollections() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst - * @see http://docs.mongodb.org/manual/reference/command/listCollections/ + * @see http://mongodb.com/docs/manual/reference/command/listCollections/ */ class CollectionInfoCommandIterator extends IteratorIterator implements CollectionInfoIterator { diff --git a/src/Model/DatabaseInfo.php b/src/Model/DatabaseInfo.php index e571e10d3..ae651a853 100644 --- a/src/Model/DatabaseInfo.php +++ b/src/Model/DatabaseInfo.php @@ -31,7 +31,7 @@ * * @api * @see \MongoDB\Client::listDatabases() - * @see http://docs.mongodb.org/manual/reference/command/listDatabases/ + * @see http://mongodb.com/docs/manual/reference/command/listDatabases/ */ class DatabaseInfo implements ArrayAccess { diff --git a/src/Model/DatabaseInfoLegacyIterator.php b/src/Model/DatabaseInfoLegacyIterator.php index 213aeb6ed..616bcca64 100644 --- a/src/Model/DatabaseInfoLegacyIterator.php +++ b/src/Model/DatabaseInfoLegacyIterator.php @@ -32,7 +32,7 @@ * * @internal * @see \MongoDB\Client::listDatabases() - * @see http://docs.mongodb.org/manual/reference/command/listDatabases/ + * @see http://mongodb.com/docs/manual/reference/command/listDatabases/ */ class DatabaseInfoLegacyIterator implements DatabaseInfoIterator { diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php index c0b513f4b..968701422 100644 --- a/src/Model/IndexInfo.php +++ b/src/Model/IndexInfo.php @@ -37,7 +37,7 @@ * @api * @see \MongoDB\Collection::listIndexes() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst - * @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/ + * @see http://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ */ class IndexInfo implements ArrayAccess { @@ -136,7 +136,7 @@ public function isGeoHaystack() /** * Return whether this is a sparse index. * - * @see http://docs.mongodb.org/manual/core/index-sparse/ + * @see http://mongodb.com/docs/manual/core/index-sparse/ * @return boolean */ public function isSparse() @@ -157,7 +157,7 @@ public function isText() /** * Return whether this is a TTL index. * - * @see http://docs.mongodb.org/manual/core/index-ttl/ + * @see http://mongodb.com/docs/manual/core/index-ttl/ * @return boolean */ public function isTtl() @@ -168,7 +168,7 @@ public function isTtl() /** * Return whether this is a unique index. * - * @see http://docs.mongodb.org/manual/core/index-unique/ + * @see http://mongodb.com/docs/manual/core/index-unique/ * @return boolean */ public function isUnique() diff --git a/src/Model/IndexInfoIteratorIterator.php b/src/Model/IndexInfoIteratorIterator.php index 84a5b9541..2410e805b 100644 --- a/src/Model/IndexInfoIteratorIterator.php +++ b/src/Model/IndexInfoIteratorIterator.php @@ -33,8 +33,8 @@ * @internal * @see \MongoDB\Collection::listIndexes() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst - * @see http://docs.mongodb.org/manual/reference/command/listIndexes/ - * @see http://docs.mongodb.org/manual/reference/system-collections/ + * @see http://mongodb.com/docs/manual/reference/command/listIndexes/ + * @see http://mongodb.com/docs/manual/reference/system-collections/ */ class IndexInfoIteratorIterator extends IteratorIterator implements IndexInfoIterator { diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php index 099c052d2..7ed36cc04 100644 --- a/src/Model/IndexInput.php +++ b/src/Model/IndexInput.php @@ -36,7 +36,7 @@ * @internal * @see \MongoDB\Collection::createIndexes() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst - * @see http://docs.mongodb.org/manual/reference/method/db.collection.createIndex/ + * @see http://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ */ class IndexInput implements Serializable { diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 6c3596b01..742540232 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -47,7 +47,7 @@ * * @api * @see \MongoDB\Collection::aggregate() - * @see http://docs.mongodb.org/manual/reference/command/aggregate/ + * @see http://mongodb.com/docs/manual/reference/command/aggregate/ */ class Aggregate implements Executable, Explainable { diff --git a/src/Operation/Count.php b/src/Operation/Count.php index f0a0983f4..28f3fbd00 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -39,7 +39,7 @@ * * @api * @see \MongoDB\Collection::count() - * @see http://docs.mongodb.org/manual/reference/command/count/ + * @see http://mongodb.com/docs/manual/reference/command/count/ */ class Count implements Executable, Explainable { diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index 76f5e35f5..bfc11fb04 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -39,7 +39,7 @@ * * @api * @see \MongoDB\Database::createCollection() - * @see http://docs.mongodb.org/manual/reference/command/create/ + * @see http://mongodb.com/docs/manual/reference/command/create/ */ class CreateCollection implements Executable { @@ -113,7 +113,7 @@ class CreateCollection implements Executable * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @see http://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb - * @see https://docs.mongodb.org/manual/core/document-validation/ + * @see https://mongodb.com/docs/manual/core/schema-validation/ * @param string $databaseName Database name * @param string $collectionName Collection name * @param array $options Command options diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php index 58c2dd6c1..4d96e6e34 100644 --- a/src/Operation/CreateIndexes.php +++ b/src/Operation/CreateIndexes.php @@ -39,7 +39,7 @@ * @api * @see \MongoDB\Collection::createIndex() * @see \MongoDB\Collection::createIndexes() - * @see http://docs.mongodb.org/manual/reference/command/createIndexes/ + * @see http://mongodb.com/docs/manual/reference/command/createIndexes/ */ class CreateIndexes implements Executable { diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 208ceb656..9bb70bfb9 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -39,7 +39,7 @@ * classes. * * @internal - * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @see http://mongodb.com/docs/manual/reference/command/delete/ */ class Delete implements Executable, Explainable { diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index f5feb0bd9..52c4d52c9 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -28,7 +28,7 @@ * * @api * @see \MongoDB\Collection::deleteOne() - * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @see http://mongodb.com/docs/manual/reference/command/delete/ */ class DeleteMany implements Executable, Explainable { diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index d8b35f7dc..941cce91c 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -28,7 +28,7 @@ * * @api * @see \MongoDB\Collection::deleteOne() - * @see http://docs.mongodb.org/manual/reference/command/delete/ + * @see http://mongodb.com/docs/manual/reference/command/delete/ */ class DeleteOne implements Executable, Explainable { diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 6d812ce39..a04e1b989 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -38,7 +38,7 @@ * * @api * @see \MongoDB\Collection::distinct() - * @see http://docs.mongodb.org/manual/reference/command/distinct/ + * @see http://mongodb.com/docs/manual/reference/command/distinct/ */ class Distinct implements Executable, Explainable { diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 51375022d..3ec109a66 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -34,7 +34,7 @@ * @api * @see \MongoDB\Collection::drop() * @see \MongoDB\Database::dropCollection() - * @see http://docs.mongodb.org/manual/reference/command/drop/ + * @see http://mongodb.com/docs/manual/reference/command/drop/ */ class DropCollection implements Executable { diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php index ad96fc869..f76fb8a94 100644 --- a/src/Operation/DropDatabase.php +++ b/src/Operation/DropDatabase.php @@ -33,7 +33,7 @@ * @api * @see \MongoDB\Client::dropDatabase() * @see \MongoDB\Database::drop() - * @see http://docs.mongodb.org/manual/reference/command/dropDatabase/ + * @see http://mongodb.com/docs/manual/reference/command/dropDatabase/ */ class DropDatabase implements Executable { diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php index a8bb5bca2..ddb0f5468 100644 --- a/src/Operation/DropIndexes.php +++ b/src/Operation/DropIndexes.php @@ -34,7 +34,7 @@ * * @api * @see \MongoDB\Collection::dropIndexes() - * @see http://docs.mongodb.org/manual/reference/command/dropIndexes/ + * @see http://mongodb.com/docs/manual/reference/command/dropIndexes/ */ class DropIndexes implements Executable { diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index 1164264fd..1aed13de3 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -36,7 +36,7 @@ * * @api * @see \MongoDB\Collection::estimatedDocumentCount() - * @see http://docs.mongodb.org/manual/reference/command/count/ + * @see http://mongodb.com/docs/manual/reference/command/count/ */ class EstimatedDocumentCount implements Executable, Explainable { diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php index f9ff3f3df..8750cdbf8 100644 --- a/src/Operation/Explain.php +++ b/src/Operation/Explain.php @@ -35,7 +35,7 @@ * * @api * @see \MongoDB\Collection::explain() - * @see http://docs.mongodb.org/manual/reference/command/explain/ + * @see http://mongodb.com/docs/manual/reference/command/explain/ */ class Explain implements Executable { diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 29b278204..b84c5bb49 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -41,8 +41,8 @@ * * @api * @see \MongoDB\Collection::find() - * @see http://docs.mongodb.org/manual/tutorial/query-documents/ - * @see http://docs.mongodb.org/manual/reference/operator/query-modifier/ + * @see http://mongodb.com/docs/manual/tutorial/query-documents/ + * @see http://mongodb.com/docs/manual/reference/operator/query-modifier/ */ class Find implements Executable, Explainable { diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 8988e003c..5c6a9f240 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -44,7 +44,7 @@ * FindOneAndUpdate operation classes. * * @internal - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindAndModify implements Executable, Explainable { diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index 6fcadf28c..aff680733 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -29,8 +29,8 @@ * * @api * @see \MongoDB\Collection::findOne() - * @see http://docs.mongodb.org/manual/tutorial/query-documents/ - * @see http://docs.mongodb.org/manual/reference/operator/query-modifier/ + * @see http://mongodb.com/docs/manual/tutorial/query-documents/ + * @see http://mongodb.com/docs/manual/reference/operator/query-modifier/ */ class FindOne implements Executable, Explainable { diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 3a5ba9b22..be764b740 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -30,7 +30,7 @@ * * @api * @see \MongoDB\Collection::findOneAndDelete() - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindOneAndDelete implements Executable, Explainable { diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 5c0147174..076907d9d 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -32,7 +32,7 @@ * * @api * @see \MongoDB\Collection::findOneAndReplace() - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindOneAndReplace implements Executable, Explainable { diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index c742fc7d3..f37f2d1ff 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::findOneAndUpdate() - * @see http://docs.mongodb.org/manual/reference/command/findAndModify/ + * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindOneAndUpdate implements Executable, Explainable { diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index 9cc869bbf..15d1de8ed 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -36,7 +36,7 @@ * * @api * @see \MongoDB\Collection::insertMany() - * @see http://docs.mongodb.org/manual/reference/command/insert/ + * @see http://mongodb.com/docs/manual/reference/command/insert/ */ class InsertMany implements Executable { diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index f2fba52f7..4a330a692 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -35,7 +35,7 @@ * * @api * @see \MongoDB\Collection::insertOne() - * @see http://docs.mongodb.org/manual/reference/command/insert/ + * @see http://mongodb.com/docs/manual/reference/command/insert/ */ class InsertOne implements Executable { diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index 678475d89..e5b77e856 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -29,7 +29,7 @@ * * @api * @see \MongoDB\Database::listCollectionNames() - * @see http://docs.mongodb.org/manual/reference/command/listCollections/ + * @see http://mongodb.com/docs/manual/reference/command/listCollections/ */ class ListCollectionNames implements Executable { diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php index bdc75f02b..8212ff26d 100644 --- a/src/Operation/ListCollections.php +++ b/src/Operation/ListCollections.php @@ -29,7 +29,7 @@ * * @api * @see \MongoDB\Database::listCollections() - * @see http://docs.mongodb.org/manual/reference/command/listCollections/ + * @see http://mongodb.com/docs/manual/reference/command/listCollections/ */ class ListCollections implements Executable { diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php index 3104f4b39..8f82b257c 100644 --- a/src/Operation/ListDatabaseNames.php +++ b/src/Operation/ListDatabaseNames.php @@ -32,7 +32,7 @@ * * @api * @see \MongoDB\Client::listDatabaseNames() - * @see http://docs.mongodb.org/manual/reference/command/ListDatabases/ + * @see https://mongodb.com/docs/manual/reference/command/listDatabases/#mongodb-dbcommand-dbcmd.listDatabases */ class ListDatabaseNames implements Executable { diff --git a/src/Operation/ListDatabases.php b/src/Operation/ListDatabases.php index 82da5fad6..8e74ba159 100644 --- a/src/Operation/ListDatabases.php +++ b/src/Operation/ListDatabases.php @@ -30,7 +30,7 @@ * * @api * @see \MongoDB\Client::listDatabases() - * @see http://docs.mongodb.org/manual/reference/command/ListDatabases/ + * @see https://mongodb.com/docs/manual/reference/command/listDatabases/#mongodb-dbcommand-dbcmd.listDatabases` */ class ListDatabases implements Executable { diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index 34d97b3d7..2574208c6 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -35,7 +35,7 @@ * * @api * @see \MongoDB\Collection::listIndexes() - * @see http://docs.mongodb.org/manual/reference/command/listIndexes/ + * @see http://mongodb.com/docs/manual/reference/command/listIndexes/ */ class ListIndexes implements Executable { diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index c71ccc34a..e7a928812 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -49,7 +49,7 @@ * * @api * @see \MongoDB\Collection::mapReduce() - * @see https://docs.mongodb.com/manual/reference/command/mapReduce/ + * @see https://mongodb.com/docs/manual/reference/command/mapReduce/ */ class MapReduce implements Executable { diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php index b38c95baf..5ffe476dc 100644 --- a/src/Operation/ModifyCollection.php +++ b/src/Operation/ModifyCollection.php @@ -32,7 +32,7 @@ * * @api * @see \MongoDB\Database::modifyCollection() - * @see http://docs.mongodb.org/manual/reference/command/collMod/ + * @see http://mongodb.com/docs/manual/reference/command/collMod/ */ class ModifyCollection implements Executable { diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php index 82ac33c2c..14402e5a3 100644 --- a/src/Operation/RenameCollection.php +++ b/src/Operation/RenameCollection.php @@ -34,7 +34,7 @@ * @api * @see \MongoDB\Collection::rename() * @see \MongoDB\Database::renameCollection() - * @see https://docs.mongodb.org/manual/reference/command/renameCollection/ + * @see https://mongodb.com/docs/manual/reference/command/renameCollection/ */ class RenameCollection implements Executable { diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index c0eef91f9..40921e794 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::replaceOne() - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ */ class ReplaceOne implements Executable { diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 09292b9d5..cbbb88f2f 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -42,7 +42,7 @@ * operation classes. * * @internal - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ */ class Update implements Executable, Explainable { diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index 58f23e972..d8fb9ea13 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::updateMany() - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ */ class UpdateMany implements Executable, Explainable { diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index f5f13d86f..b1ead711a 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::updateOne() - * @see http://docs.mongodb.org/manual/reference/command/update/ + * @see http://mongodb.com/docs/manual/reference/command/update/ */ class UpdateOne implements Executable, Explainable { diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index a0a315677..db752d99b 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -52,7 +52,7 @@ * * @api * @see \MongoDB\Collection::watch() - * @see https://docs.mongodb.com/manual/changeStreams/ + * @see https://mongodb.com/docs/manual/changeStreams/ */ class Watch implements Executable, /* @internal */ CommandSubscriber { diff --git a/src/functions.php b/src/functions.php index 3c99e0424..c838d3075 100644 --- a/src/functions.php +++ b/src/functions.php @@ -239,7 +239,7 @@ function is_last_pipeline_operator_write(array $pipeline): bool * This is used to determine if a mapReduce command requires a primary. * * @internal - * @see https://docs.mongodb.com/manual/reference/command/mapReduce/#output-inline + * @see https://mongodb.com/docs/manual/reference/command/mapReduce/#output-inline * @param string|array|object $out Output specification * @return boolean * @throws InvalidArgumentException @@ -274,7 +274,7 @@ function is_mapreduce_output_inline($out): bool * check the fsync option since that was never supported in the PHP driver. * * @internal - * @see https://docs.mongodb.com/manual/reference/write-concern/ + * @see https://mongodb.com/docs/manual/reference/write-concern/ * @param WriteConcern $writeConcern * @return boolean */ diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index fad3da65f..e1e9fc982 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -354,7 +354,7 @@ public function testRenameToDifferentDatabase(): void /* When renaming an unsharded collection, mongos requires the source * and target database to both exist on the primary shard. In practice, * this means we need to create the target database explicitly. - * See: https://docs.mongodb.com/manual/reference/command/renameCollection/#unsharded-collections + * See: https://mongodb.com/docs/manual/reference/command/renameCollection/#unsharded-collections */ if ($this->isShardedCluster()) { $toDatabase->foo->insertOne(['_id' => 1]); diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 72a7cadaf..180762384 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -258,7 +258,7 @@ public function testRenameCollectionToDifferentDatabase(): void /* When renaming an unsharded collection, mongos requires the source * and target database to both exist on the primary shard. In practice, this * means we need to create the target database explicitly. - * See: https://docs.mongodb.com/manual/reference/command/renameCollection/#unsharded-collections + * See: https://mongodb.com/docs/manual/reference/command/renameCollection/#unsharded-collections */ if ($this->isShardedCluster()) { $toDatabase->foo->insertOne(['_id' => 1]); diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index b7fb8ce4d..b4beb1b39 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1289,7 +1289,7 @@ public function testTransactions_intro_example_1(): void $client = static::createTestClient(); - /* The WC is required: https://docs.mongodb.com/manual/core/transactions/#transactions-and-locks */ + /* The WC is required: https://mongodb.com/docs/manual/core/transactions/#transactions-and-locks */ $client->hr->dropCollection('employees', ['writeConcern' => new WriteConcern('majority')]); $client->reporting->dropCollection('events', ['writeConcern' => new WriteConcern('majority')]); @@ -1469,7 +1469,7 @@ public function testTransactions_retry_example_3(): void $client = static::createTestClient(); - /* The WC is required: https://docs.mongodb.com/manual/core/transactions/#transactions-and-locks */ + /* The WC is required: https://mongodb.com/docs/manual/core/transactions/#transactions-and-locks */ $client->hr->dropCollection('employees', ['writeConcern' => new WriteConcern('majority')]); $client->reporting->dropCollection('events', ['writeConcern' => new WriteConcern('majority')]); From f74b0d342e6f5fd510525b9dc4487b05894e067b Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 30 Mar 2022 14:55:44 -0400 Subject: [PATCH 122/321] PHPLIB-827: Use https links in documentation and comments (#907) Remove redundant www subdomains from URLs. The Apache license links are intentionally left as-is Also updates outdated ICU link, which had no https equivalent. --- .github/ISSUE_TEMPLATE/bug-report.md | 4 +-- CONTRIBUTING.md | 8 ++--- ...-MongoDBClient-method-construct-param.yaml | 4 +-- docs/reference/bson.txt | 2 +- docs/tutorial/collation.txt | 2 +- docs/upgrade.txt | 2 +- src/BulkWriteResult.php | 2 +- src/ChangeStream.php | 12 +++---- src/Client.php | 20 +++++------ src/Collection.php | 36 +++++++++---------- src/Command/ListCollections.php | 6 ++-- src/Command/ListDatabases.php | 6 ++-- src/Database.php | 12 +++---- src/DeleteResult.php | 2 +- src/Exception/BadMethodCallException.php | 2 +- src/Exception/Exception.php | 2 +- src/Exception/InvalidArgumentException.php | 2 +- src/Exception/ResumeTokenException.php | 2 +- src/Exception/RuntimeException.php | 2 +- src/Exception/UnexpectedValueException.php | 2 +- src/Exception/UnsupportedException.php | 2 +- src/GridFS/Bucket.php | 8 ++--- src/GridFS/CollectionWrapper.php | 2 +- src/GridFS/Exception/CorruptFileException.php | 2 +- .../Exception/FileNotFoundException.php | 2 +- src/GridFS/ReadableStream.php | 4 +-- src/GridFS/StreamWrapper.php | 18 +++++----- src/GridFS/WritableStream.php | 4 +-- src/InsertManyResult.php | 2 +- src/InsertOneResult.php | 2 +- src/MapReduceResult.php | 4 +-- src/Model/BSONArray.php | 12 +++---- src/Model/BSONDocument.php | 14 ++++---- src/Model/BSONIterator.php | 14 ++++---- src/Model/CachingIterator.php | 14 ++++---- src/Model/CallbackIterator.php | 12 +++---- src/Model/ChangeStreamIterator.php | 2 +- src/Model/CollectionInfo.php | 12 +++---- src/Model/CollectionInfoCommandIterator.php | 6 ++-- src/Model/CollectionInfoIterator.php | 2 +- src/Model/DatabaseInfo.php | 14 ++++---- src/Model/DatabaseInfoIterator.php | 2 +- src/Model/DatabaseInfoLegacyIterator.php | 14 ++++---- src/Model/IndexInfo.php | 20 +++++------ src/Model/IndexInfoIterator.php | 2 +- src/Model/IndexInfoIteratorIterator.php | 8 ++--- src/Model/IndexInput.php | 6 ++-- src/Operation/Aggregate.php | 10 +++--- src/Operation/BulkWrite.php | 6 ++-- src/Operation/Count.php | 6 ++-- src/Operation/CountDocuments.php | 2 +- src/Operation/CreateCollection.php | 8 ++--- src/Operation/CreateIndexes.php | 6 ++-- src/Operation/DatabaseCommand.php | 4 +-- src/Operation/Delete.php | 6 ++-- src/Operation/DeleteMany.php | 4 +-- src/Operation/DeleteOne.php | 4 +-- src/Operation/Distinct.php | 6 ++-- src/Operation/DropCollection.php | 6 ++-- src/Operation/DropDatabase.php | 6 ++-- src/Operation/DropIndexes.php | 6 ++-- src/Operation/EstimatedDocumentCount.php | 4 +-- src/Operation/Executable.php | 2 +- src/Operation/Explain.php | 6 ++-- src/Operation/Explainable.php | 2 +- src/Operation/Find.php | 8 ++--- src/Operation/FindAndModify.php | 6 ++-- src/Operation/FindOne.php | 6 ++-- src/Operation/FindOneAndDelete.php | 4 +-- src/Operation/FindOneAndReplace.php | 4 +-- src/Operation/FindOneAndUpdate.php | 4 +-- src/Operation/InsertMany.php | 8 ++--- src/Operation/InsertOne.php | 8 ++--- src/Operation/ListCollectionNames.php | 4 +-- src/Operation/ListCollections.php | 4 +-- src/Operation/ListDatabaseNames.php | 2 +- src/Operation/ListDatabases.php | 2 +- src/Operation/ListIndexes.php | 6 ++-- src/Operation/MapReduce.php | 6 ++-- src/Operation/ModifyCollection.php | 6 ++-- src/Operation/RenameCollection.php | 4 +-- src/Operation/ReplaceOne.php | 4 +-- src/Operation/Update.php | 8 ++--- src/Operation/UpdateMany.php | 4 +-- src/Operation/UpdateOne.php | 4 +-- src/Operation/Watch.php | 2 +- src/UpdateResult.php | 2 +- src/functions.php | 2 +- tests/SpecTests/CommandExpectations.php | 6 ++-- tests/UnifiedSpecTests/EntityMap.php | 8 ++--- tests/UnifiedSpecTests/EventCollector.php | 6 ++-- tests/UnifiedSpecTests/EventObserver.php | 6 ++-- tests/UnifiedSpecTests/FailPointObserver.php | 6 ++-- tests/UnifiedSpecTests/UnifiedTestCase.php | 4 +-- 94 files changed, 286 insertions(+), 286 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md index 996a7c95b..df9469e7a 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -67,7 +67,7 @@ reproduced with PHP's built-in web server[^3]. If not, please share your web server version and any relevant configuration details in the Environment section above. -[^3]: http://php.net/manual/en/features.commandline.webserver.php +[^3]: https://php.net/manual/en/features.commandline.webserver.php --> ### Expected and Actual Behavior @@ -90,5 +90,5 @@ If the issue relates to internal driver behavior (e.g. connection issues), please include a debug log[^5]. This may be generated by setting the `mongodb.debug` INI option to "stderr" or a directory (useful for web SAPIs). -[^5]: https://www.php.net/manual/en/mongodb.configuration.php#ini.mongodb.debug +[^5]: https://php.net/manual/en/mongodb.configuration.php#ini.mongodb.debug --> diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6922de74..2c035af5e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ $ composer update In addition to installing project dependencies, Composer will check that the required extension version is installed. Directions for installing the extension -may be found [here](http://php.net/manual/en/mongodb.installation.php). +may be found [here](https://php.net/manual/en/mongodb.installation.php). Installation directions for Composer may be found in its [Getting Started](https://getcomposer.org/doc/00-intro.md) guide. @@ -146,7 +146,7 @@ page. ### Update version info -The PHP library uses [semantic versioning](http://semver.org/). Do not break +The PHP library uses [semantic versioning](https://semver.org/). Do not break backwards compatibility in a non-major release or your users will kill you. Before proceeding, ensure that the `master` branch is up-to-date with all code @@ -205,7 +205,7 @@ This library may be installed or upgraded with: composer require mongodb/mongodb^X.Y.Z -Installation instructions for the `mongodb` extension may be found in the [PHP.net documentation](https://www.php.net/manual/en/mongodb.installation.php). +Installation instructions for the `mongodb` extension may be found in the [PHP.net documentation](https://php.net/manual/en/mongodb.installation.php). ``` The URL for the list of resolved JIRA issues will need to be updated with each @@ -223,7 +223,7 @@ Thanks for our community contributors for this release: * [$CONTRIBUTOR_NAME](https://github.com/$GITHUB_USERNAME) ``` -Release announcements should also be posted in the [MongoDB Product & Driver Announcements: Driver Releases](https://www.mongodb.com/community/forums/tags/c/announcements/driver-releases/110/php) forum and shared on Twitter. +Release announcements should also be posted in the [MongoDB Product & Driver Announcements: Driver Releases](https://mongodb.com/community/forums/tags/c/announcements/driver-releases/110/php) forum and shared on Twitter. ### Documentation Updates for New Major and Minor Versions diff --git a/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml b/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml index 4b6ff4205..62998287e 100644 --- a/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-construct-param.yaml @@ -9,7 +9,7 @@ description: | Defaults to ``"mongodb://127.0.0.1:27017"`` if unspecified. Any special characters in the URI components need to be encoded according to - `RFC 3986 `_. This is particularly + `RFC 3986 `_. This is particularly relevant to the username and password, which can often include special characters such as ``@``, ``:``, or ``%``. When connecting via a Unix domain socket, the socket path may contain special characters such as slashes and @@ -26,7 +26,7 @@ description: | Specifies additional URI options, such as authentication credentials or query string parameters. The options specified in ``$uriOptions`` take precedence over any analogous options present in the ``$uri`` string and do not need to - be encoded according to `RFC 3986 `_. + be encoded according to `RFC 3986 `_. Refer to the :php:`MongoDB\\Driver\\Manager::__construct() ` extension reference and :manual:`MongoDB diff --git a/docs/reference/bson.txt b/docs/reference/bson.txt index b465ef619..2d4851a12 100644 --- a/docs/reference/bson.txt +++ b/docs/reference/bson.txt @@ -15,7 +15,7 @@ Overview MongoDB stores data records as BSON documents. BSON is a binary representation of :term:`JSON` documents, though it contains more data types than JSON. For the -BSON spec, see `bsonspec.org `_. +BSON spec, see `bsonspec.org `_. By default, the |php-library| returns BSON documents as :phpclass:`MongoDB\\Model\\BSONDocument` objects and BSON arrays as diff --git a/docs/tutorial/collation.txt b/docs/tutorial/collation.txt index 7145de0d8..76df18fe7 100644 --- a/docs/tutorial/collation.txt +++ b/docs/tutorial/collation.txt @@ -66,7 +66,7 @@ Collation Parameters ] The only required parameter is ``locale``, which the server parses as an `ICU -format locale ID `_. For example, set +format locale ID `_. For example, set ``locale`` to ``en_US`` to represent US English or ``fr_CA`` to represent Canadian French. diff --git a/docs/upgrade.txt b/docs/upgrade.txt index b785b6557..b3d9ab38d 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -28,7 +28,7 @@ BSON Type Classes When upgrading from the legacy driver, type classes such as MongoId must be replaced with classes in the -`MongoDB\\BSON namespace `_. The +`MongoDB\\BSON namespace `_. The new driver also introduces interfaces for its BSON types, which should be preferred if applications need to type hint against BSON values. diff --git a/src/BulkWriteResult.php b/src/BulkWriteResult.php index ad0a57c06..1a1f3ed41 100644 --- a/src/BulkWriteResult.php +++ b/src/BulkWriteResult.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/ChangeStream.php b/src/ChangeStream.php index 9cdf73550..551024198 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -100,7 +100,7 @@ public function __construct(ChangeStreamIterator $iterator, callable $resumeCall } /** - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return mixed */ #[ReturnTypeWillChange] @@ -132,7 +132,7 @@ public function getResumeToken() } /** - * @see http://php.net/iterator.key + * @see https://php.net/iterator.key * @return mixed */ #[ReturnTypeWillChange] @@ -146,7 +146,7 @@ public function key() } /** - * @see http://php.net/iterator.next + * @see https://php.net/iterator.next * @return void * @throws ResumeTokenException */ @@ -162,7 +162,7 @@ public function next() } /** - * @see http://php.net/iterator.rewind + * @see https://php.net/iterator.rewind * @return void * @throws ResumeTokenException */ @@ -181,7 +181,7 @@ public function rewind() } /** - * @see http://php.net/iterator.valid + * @see https://php.net/iterator.valid * @return boolean */ #[ReturnTypeWillChange] diff --git a/src/Client.php b/src/Client.php index ffb879505..181ac733c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -88,9 +88,9 @@ class Client * * Other options are documented in MongoDB\Driver\Manager::__construct(). * - * @see http://mongodb.com/docs/manual/reference/connection-string/ - * @see http://php.net/manual/en/mongodb-driver-manager.construct.php - * @see http://php.net/manual/en/mongodb.persistence.php#mongodb.persistence.typemaps + * @see https://mongodb.com/docs/manual/reference/connection-string/ + * @see https://php.net/manual/en/mongodb-driver-manager.construct.php + * @see https://php.net/manual/en/mongodb.persistence.php#mongodb.persistence.typemaps * @param string $uri MongoDB connection string * @param array $uriOptions Additional connection string options * @param array $driverOptions Driver-specific options @@ -130,7 +130,7 @@ public function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [ /** * Return internal properties for debugging purposes. * - * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -150,8 +150,8 @@ public function __debugInfo() * be selected with complex syntax (e.g. $client->{"that-database"}) or * {@link selectDatabase()}. * - * @see http://php.net/oop5.overloading#object.get - * @see http://php.net/types.string#language.types.string.parsing.complex + * @see https://php.net/oop5.overloading#object.get + * @see https://php.net/types.string#language.types.string.parsing.complex * @param string $databaseName Name of the database to select * @return Database */ @@ -231,7 +231,7 @@ public function getManager() /** * Return the read concern for this client. * - * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-readconcern.isdefault.php * @return ReadConcern */ public function getReadConcern() @@ -262,7 +262,7 @@ public function getTypeMap() /** * Return the write concern for this client. * - * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php * @return WriteConcern */ public function getWriteConcern() @@ -340,7 +340,7 @@ public function selectDatabase($databaseName, array $options = []) /** * Start a new client session. * - * @see http://php.net/manual/en/mongodb-driver-manager.startsession.php + * @see https://php.net/manual/en/mongodb-driver-manager.startsession.php * @param array $options Session options * @return Session */ diff --git a/src/Collection.php b/src/Collection.php index 33205214f..df53fb709 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -164,7 +164,7 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar /** * Return internal properties for debugging purposes. * - * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -368,8 +368,8 @@ public function createIndex($key, array $options = []) * If the "name" option is unspecified, a name will be generated from the * "key" document. * - * @see http://mongodb.com/docs/manual/reference/command/createIndexes/ - * @see http://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ + * @see https://mongodb.com/docs/manual/reference/command/createIndexes/ + * @see https://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ * @see CreateIndexes::__construct() for supported command options * @param array[] $indexes List of index specifications * @param array $options Command options @@ -395,7 +395,7 @@ public function createIndexes(array $indexes, array $options = []) * Deletes all documents matching the filter. * * @see DeleteMany::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/delete/ + * @see https://mongodb.com/docs/manual/reference/command/delete/ * @param array|object $filter Query by which to delete documents * @param array $options Command options * @return DeleteResult @@ -419,7 +419,7 @@ public function deleteMany($filter, array $options = []) * Deletes at most one document matching the filter. * * @see DeleteOne::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/delete/ + * @see https://mongodb.com/docs/manual/reference/command/delete/ * @param array|object $filter Query by which to delete documents * @param array $options Command options * @return DeleteResult @@ -593,7 +593,7 @@ public function estimatedDocumentCount(array $options = []) * Explains explainable commands. * * @see Explain::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/explain/ + * @see https://mongodb.com/docs/manual/reference/command/explain/ * @param Explainable $explainable Command on which to run explain * @param array $options Additional options * @return array|object @@ -690,7 +690,7 @@ public function findOne($filter = [], array $options = []) * The document to return may be null if no document matched the filter. * * @see FindOneAndDelete::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ * @param array|object $filter Query by which to filter documents * @param array $options Command options * @return array|object|null @@ -726,7 +726,7 @@ public function findOneAndDelete($filter, array $options = []) * to return the updated document. * * @see FindOneAndReplace::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ * @param array|object $filter Query by which to filter documents * @param array|object $replacement Replacement document * @param array $options Command options @@ -763,7 +763,7 @@ public function findOneAndReplace($filter, $replacement, array $options = []) * to return the updated document. * * @see FindOneAndReplace::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ * @param array|object $filter Query by which to filter documents * @param array|object $update Update to apply to the matched document * @param array $options Command options @@ -834,7 +834,7 @@ public function getNamespace() /** * Return the read concern for this collection. * - * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-readconcern.isdefault.php * @return ReadConcern */ public function getReadConcern() @@ -865,7 +865,7 @@ public function getTypeMap() /** * Return the write concern for this collection. * - * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php * @return WriteConcern */ public function getWriteConcern() @@ -877,7 +877,7 @@ public function getWriteConcern() * Inserts multiple documents. * * @see InsertMany::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/insert/ + * @see https://mongodb.com/docs/manual/reference/command/insert/ * @param array[]|object[] $documents The documents to insert * @param array $options Command options * @return InsertManyResult @@ -900,7 +900,7 @@ public function insertMany(array $documents, array $options = []) * Inserts one document. * * @see InsertOne::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/insert/ + * @see https://mongodb.com/docs/manual/reference/command/insert/ * @param array|object $document The document to insert * @param array $options Command options * @return InsertOneResult @@ -940,7 +940,7 @@ public function listIndexes(array $options = []) * Executes a map-reduce aggregation on the collection. * * @see MapReduce::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/mapReduce/ + * @see https://mongodb.com/docs/manual/reference/command/mapReduce/ * @param JavascriptInterface $map Map function * @param JavascriptInterface $reduce Reduce function * @param string|array|object $out Output specification @@ -1025,7 +1025,7 @@ public function rename(string $toCollectionName, ?string $toDatabaseName = null, * Replaces at most one document matching the filter. * * @see ReplaceOne::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ * @param array|object $filter Query by which to filter documents * @param array|object $replacement Replacement document * @param array $options Command options @@ -1050,7 +1050,7 @@ public function replaceOne($filter, $replacement, array $options = []) * Updates all documents matching the filter. * * @see UpdateMany::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ * @param array|object $filter Query by which to filter documents * @param array|object $update Update to apply to the matched documents * @param array $options Command options @@ -1075,7 +1075,7 @@ public function updateMany($filter, $update, array $options = []) * Updates at most one document matching the filter. * * @see UpdateOne::__construct() for supported options - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ * @param array|object $filter Query by which to filter documents * @param array|object $update Update to apply to the matched document * @param array $options Command options diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index b09cc8722..100604170 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -34,7 +34,7 @@ * Wrapper for the listCollections command. * * @internal - * @see http://mongodb.com/docs/manual/reference/command/listCollections/ + * @see https://mongodb.com/docs/manual/reference/command/listCollections/ */ class ListCollections implements Executable { @@ -129,7 +129,7 @@ public function execute(Server $server) * Note: read preference is intentionally omitted, as the spec requires that * the command be executed on the primary. * - * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php * @return array */ private function createOptions() diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index 26a5e6de3..20c03157f 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -35,7 +35,7 @@ * Wrapper for the ListDatabases command. * * @internal - * @see http://mongodb.com/docs/manual/reference/command/listDatabases/ + * @see https://mongodb.com/docs/manual/reference/command/listDatabases/ */ class ListDatabases implements Executable { @@ -131,7 +131,7 @@ public function execute(Server $server) * Note: read preference is intentionally omitted, as the spec requires that * the command be executed on the primary. * - * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php * @return array */ private function createOptions() diff --git a/src/Database.php b/src/Database.php index b790f90ae..72e44e507 100644 --- a/src/Database.php +++ b/src/Database.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -136,7 +136,7 @@ public function __construct(Manager $manager, $databaseName, array $options = [] /** * Return internal properties for debugging purposes. * - * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -158,8 +158,8 @@ public function __debugInfo() * be selected with complex syntax (e.g. $database->{"system.profile"}) or * {@link selectCollection()}. * - * @see http://php.net/oop5.overloading#object.get - * @see http://php.net/types.string#language.types.string.parsing.complex + * @see https://php.net/oop5.overloading#object.get + * @see https://php.net/types.string#language.types.string.parsing.complex * @param string $collectionName Name of the collection to select * @return Collection */ @@ -358,7 +358,7 @@ public function getManager() /** * Return the read concern for this database. * - * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-readconcern.isdefault.php * @return ReadConcern */ public function getReadConcern() @@ -389,7 +389,7 @@ public function getTypeMap() /** * Return the write concern for this database. * - * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php * @return WriteConcern */ public function getWriteConcern() diff --git a/src/DeleteResult.php b/src/DeleteResult.php index d0ea71cb5..5666307f2 100644 --- a/src/DeleteResult.php +++ b/src/DeleteResult.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/BadMethodCallException.php b/src/Exception/BadMethodCallException.php index f09d45d0e..99dcd6a72 100644 --- a/src/Exception/BadMethodCallException.php +++ b/src/Exception/BadMethodCallException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php index 13590e86b..7bb3e0d3f 100644 --- a/src/Exception/Exception.php +++ b/src/Exception/Exception.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index e545cacdc..8be0de2bb 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/ResumeTokenException.php b/src/Exception/ResumeTokenException.php index 09b4782b0..4d3b23188 100644 --- a/src/Exception/ResumeTokenException.php +++ b/src/Exception/ResumeTokenException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/RuntimeException.php b/src/Exception/RuntimeException.php index f9447123e..293d17913 100644 --- a/src/Exception/RuntimeException.php +++ b/src/Exception/RuntimeException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/UnexpectedValueException.php b/src/Exception/UnexpectedValueException.php index bb41f1795..fb47b1a1a 100644 --- a/src/Exception/UnexpectedValueException.php +++ b/src/Exception/UnexpectedValueException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Exception/UnsupportedException.php b/src/Exception/UnsupportedException.php index de0f7a895..51d3c84b8 100644 --- a/src/Exception/UnsupportedException.php +++ b/src/Exception/UnsupportedException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php index 6aba5eacc..cdf1cddc3 100644 --- a/src/GridFS/Bucket.php +++ b/src/GridFS/Bucket.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -196,7 +196,7 @@ public function __construct(Manager $manager, $databaseName, array $options = [] /** * Return internal properties for debugging purposes. * - * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -434,7 +434,7 @@ public function getFilesCollection() /** * Return the read concern for this GridFS bucket. * - * @see http://php.net/manual/en/mongodb-driver-readconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-readconcern.isdefault.php * @return ReadConcern */ public function getReadConcern() @@ -465,7 +465,7 @@ public function getTypeMap() /** * Return the write concern for this GridFS bucket. * - * @see http://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php + * @see https://php.net/manual/en/mongodb-driver-writeconcern.isdefault.php * @return WriteConcern */ public function getWriteConcern() diff --git a/src/GridFS/CollectionWrapper.php b/src/GridFS/CollectionWrapper.php index 69516f7c8..7b58a4fb7 100644 --- a/src/GridFS/CollectionWrapper.php +++ b/src/GridFS/CollectionWrapper.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/GridFS/Exception/CorruptFileException.php b/src/GridFS/Exception/CorruptFileException.php index b93d09bdc..c68ceec95 100644 --- a/src/GridFS/Exception/CorruptFileException.php +++ b/src/GridFS/Exception/CorruptFileException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/GridFS/Exception/FileNotFoundException.php b/src/GridFS/Exception/FileNotFoundException.php index 715e77584..ff9c2c7eb 100644 --- a/src/GridFS/Exception/FileNotFoundException.php +++ b/src/GridFS/Exception/FileNotFoundException.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/GridFS/ReadableStream.php b/src/GridFS/ReadableStream.php index 08a97a3f8..5a5b1ec3b 100644 --- a/src/GridFS/ReadableStream.php +++ b/src/GridFS/ReadableStream.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -103,7 +103,7 @@ public function __construct(CollectionWrapper $collectionWrapper, stdClass $file /** * Return internal properties for debugging purposes. * - * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index 67baaf287..3507708cb 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -89,7 +89,7 @@ public static function register($protocol = 'gridfs') /** * Closes the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-close.php + * @see https://php.net/manual/en/streamwrapper.stream-close.php */ public function stream_close() { @@ -103,7 +103,7 @@ public function stream_close() /** * Returns whether the file pointer is at the end of the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-eof.php + * @see https://php.net/manual/en/streamwrapper.stream-eof.php * @return boolean */ public function stream_eof() @@ -118,7 +118,7 @@ public function stream_eof() /** * Opens the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-open.php + * @see https://php.net/manual/en/streamwrapper.stream-open.php * @param string $path Path to the file resource * @param string $mode Mode used to open the file (only "r" and "w" are supported) * @param integer $options Additional flags set by the streams API @@ -147,7 +147,7 @@ public function stream_open($path, $mode, $options, &$openedPath) * Note: this method may return a string smaller than the requested length * if data is not available to be read. * - * @see http://php.net/manual/en/streamwrapper.stream-read.php + * @see https://php.net/manual/en/streamwrapper.stream-read.php * @param integer $length Number of bytes to read * @return string */ @@ -163,7 +163,7 @@ public function stream_read($length) /** * Return the current position of the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-seek.php + * @see https://php.net/manual/en/streamwrapper.stream-seek.php * @param integer $offset Stream offset to seek to * @param integer $whence One of SEEK_SET, SEEK_CUR, or SEEK_END * @return boolean True if the position was updated and false otherwise @@ -197,7 +197,7 @@ public function stream_seek($offset, $whence = SEEK_SET) /** * Return information about the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-stat.php + * @see https://php.net/manual/en/streamwrapper.stream-stat.php * @return array */ public function stream_stat() @@ -227,7 +227,7 @@ public function stream_stat() /** * Return the current position of the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-tell.php + * @see https://php.net/manual/en/streamwrapper.stream-tell.php * @return integer The current position of the stream */ public function stream_tell() @@ -238,7 +238,7 @@ public function stream_tell() /** * Write bytes to the stream. * - * @see http://php.net/manual/en/streamwrapper.stream-write.php + * @see https://php.net/manual/en/streamwrapper.stream-write.php * @param string $data Data to write * @return integer The number of bytes written */ diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php index f015a133f..d38d39f8e 100644 --- a/src/GridFS/WritableStream.php +++ b/src/GridFS/WritableStream.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -153,7 +153,7 @@ public function __construct(CollectionWrapper $collectionWrapper, $filename, arr /** * Return internal properties for debugging purposes. * - * @see http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo + * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() diff --git a/src/InsertManyResult.php b/src/InsertManyResult.php index da7e9382a..5dc29a8d2 100644 --- a/src/InsertManyResult.php +++ b/src/InsertManyResult.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/InsertOneResult.php b/src/InsertOneResult.php index feee39e9f..32a14a1e3 100644 --- a/src/InsertOneResult.php +++ b/src/InsertOneResult.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/MapReduceResult.php b/src/MapReduceResult.php index f9cb503a2..fe2127902 100644 --- a/src/MapReduceResult.php +++ b/src/MapReduceResult.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -85,7 +85,7 @@ public function getExecutionTimeMS() /** * Return the mapReduce results as a Traversable. * - * @see http://php.net/iteratoraggregate.getiterator + * @see https://php.net/iteratoraggregate.getiterator * @return Traversable */ #[ReturnTypeWillChange] diff --git a/src/Model/BSONArray.php b/src/Model/BSONArray.php index 3594d80ad..0b49fd98f 100644 --- a/src/Model/BSONArray.php +++ b/src/Model/BSONArray.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -49,8 +49,8 @@ public function __clone() /** * Factory method for var_export(). * - * @see http://php.net/oop5.magic#object.set-state - * @see http://php.net/var-export + * @see https://php.net/oop5.magic#object.set-state + * @see https://php.net/var-export * @param array $properties * @return self */ @@ -68,7 +68,7 @@ public static function __set_state(array $properties) * The array data will be numerically reindexed to ensure that it is stored * as a BSON array. * - * @see http://php.net/mongodb-bson-serializable.bsonserialize + * @see https://php.net/mongodb-bson-serializable.bsonserialize * @return array */ public function bsonSerialize() @@ -79,7 +79,7 @@ public function bsonSerialize() /** * Unserialize the document to BSON. * - * @see http://php.net/mongodb-bson-unserializable.bsonunserialize + * @see https://php.net/mongodb-bson-unserializable.bsonunserialize * @param array $data Array data */ public function bsonUnserialize(array $data) @@ -93,7 +93,7 @@ public function bsonUnserialize(array $data) * The array data will be numerically reindexed to ensure that it is stored * as a JSON array. * - * @see http://php.net/jsonserializable.jsonserialize + * @see https://php.net/jsonserializable.jsonserialize * @return array */ #[ReturnTypeWillChange] diff --git a/src/Model/BSONDocument.php b/src/Model/BSONDocument.php index 901ee179d..ab8cb5375 100644 --- a/src/Model/BSONDocument.php +++ b/src/Model/BSONDocument.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -49,7 +49,7 @@ public function __clone() * This overrides the parent constructor to allow property access of entries * by default. * - * @see http://php.net/arrayobject.construct + * @see https://php.net/arrayobject.construct * @param array $input * @param integer $flags * @param string $iteratorClass @@ -62,8 +62,8 @@ public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $ /** * Factory method for var_export(). * - * @see http://php.net/oop5.magic#object.set-state - * @see http://php.net/var-export + * @see https://php.net/oop5.magic#object.set-state + * @see https://php.net/var-export * @param array $properties * @return self */ @@ -78,7 +78,7 @@ public static function __set_state(array $properties) /** * Serialize the document to BSON. * - * @see http://php.net/mongodb-bson-serializable.bsonserialize + * @see https://php.net/mongodb-bson-serializable.bsonserialize * @return object */ public function bsonSerialize() @@ -89,7 +89,7 @@ public function bsonSerialize() /** * Unserialize the document to BSON. * - * @see http://php.net/mongodb-bson-unserializable.bsonunserialize + * @see https://php.net/mongodb-bson-unserializable.bsonunserialize * @param array $data Array data */ public function bsonUnserialize(array $data) @@ -100,7 +100,7 @@ public function bsonUnserialize(array $data) /** * Serialize the array to JSON. * - * @see http://php.net/jsonserializable.jsonserialize + * @see https://php.net/jsonserializable.jsonserialize * @return object */ #[ReturnTypeWillChange] diff --git a/src/Model/BSONIterator.php b/src/Model/BSONIterator.php index da90efb86..5c086b81a 100644 --- a/src/Model/BSONIterator.php +++ b/src/Model/BSONIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -63,7 +63,7 @@ class BSONIterator implements Iterator * * typeMap (array): Type map for BSON deserialization. * * @internal - * @see http://php.net/manual/en/function.mongodb.bson-tophp.php + * @see https://php.net/manual/en/function.mongodb.bson-tophp.php * @param string $data Concatenated, valid, BSON-encoded documents * @param array $options Iterator options * @throws InvalidArgumentException for parameter/option parsing errors @@ -84,7 +84,7 @@ public function __construct($data, array $options = []) } /** - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return mixed */ #[ReturnTypeWillChange] @@ -94,7 +94,7 @@ public function current() } /** - * @see http://php.net/iterator.key + * @see https://php.net/iterator.key * @return mixed */ #[ReturnTypeWillChange] @@ -104,7 +104,7 @@ public function key() } /** - * @see http://php.net/iterator.next + * @see https://php.net/iterator.next * @return void */ #[ReturnTypeWillChange] @@ -116,7 +116,7 @@ public function next() } /** - * @see http://php.net/iterator.rewind + * @see https://php.net/iterator.rewind * @return void */ #[ReturnTypeWillChange] @@ -129,7 +129,7 @@ public function rewind() } /** - * @see http://php.net/iterator.valid + * @see https://php.net/iterator.valid * @return boolean */ #[ReturnTypeWillChange] diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index 3bd474843..0e54dc2c8 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -71,7 +71,7 @@ public function __construct(Traversable $traversable) } /** - * @see http://php.net/countable.count + * @see https://php.net/countable.count * @return integer */ #[ReturnTypeWillChange] @@ -83,7 +83,7 @@ public function count() } /** - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return mixed */ #[ReturnTypeWillChange] @@ -95,7 +95,7 @@ public function current() } /** - * @see http://php.net/iterator.key + * @see https://php.net/iterator.key * @return mixed */ #[ReturnTypeWillChange] @@ -107,7 +107,7 @@ public function key() } /** - * @see http://php.net/iterator.next + * @see https://php.net/iterator.next * @return void */ #[ReturnTypeWillChange] @@ -126,7 +126,7 @@ public function next() } /** - * @see http://php.net/iterator.rewind + * @see https://php.net/iterator.rewind * @return void */ #[ReturnTypeWillChange] @@ -143,7 +143,7 @@ public function rewind() } /** - * @see http://php.net/iterator.valid + * @see https://php.net/iterator.valid * @return boolean */ #[ReturnTypeWillChange] diff --git a/src/Model/CallbackIterator.php b/src/Model/CallbackIterator.php index 9d0448dc1..a5abec9c1 100644 --- a/src/Model/CallbackIterator.php +++ b/src/Model/CallbackIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -43,7 +43,7 @@ public function __construct(Traversable $traversable, Closure $callback) } /** - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return mixed */ #[ReturnTypeWillChange] @@ -53,7 +53,7 @@ public function current() } /** - * @see http://php.net/iterator.key + * @see https://php.net/iterator.key * @return mixed */ #[ReturnTypeWillChange] @@ -63,7 +63,7 @@ public function key() } /** - * @see http://php.net/iterator.next + * @see https://php.net/iterator.next * @return void */ #[ReturnTypeWillChange] @@ -73,7 +73,7 @@ public function next() } /** - * @see http://php.net/iterator.rewind + * @see https://php.net/iterator.rewind * @return void */ #[ReturnTypeWillChange] @@ -83,7 +83,7 @@ public function rewind() } /** - * @see http://php.net/iterator.valid + * @see https://php.net/iterator.valid * @return boolean */ #[ReturnTypeWillChange] diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index bb97aa5c3..f8c40c1b5 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php index 7efdd8d6e..0513125ca 100644 --- a/src/Model/CollectionInfo.php +++ b/src/Model/CollectionInfo.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -50,7 +50,7 @@ public function __construct(array $info) /** * Return the collection info as an array. * - * @see http://php.net/oop5.magic#language.oop5.magic.debuginfo + * @see https://php.net/oop5.magic#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -153,7 +153,7 @@ public function isCapped() /** * Check whether a field exists in the collection information. * - * @see http://php.net/arrayaccess.offsetexists + * @see https://php.net/arrayaccess.offsetexists * @param mixed $key * @return boolean */ @@ -166,7 +166,7 @@ public function offsetExists($key) /** * Return the field's value from the collection information. * - * @see http://php.net/arrayaccess.offsetget + * @see https://php.net/arrayaccess.offsetget * @param mixed $key * @return mixed */ @@ -179,7 +179,7 @@ public function offsetGet($key) /** * Not supported. * - * @see http://php.net/arrayaccess.offsetset + * @see https://php.net/arrayaccess.offsetset * @param mixed $key * @param mixed $value * @throws BadMethodCallException @@ -194,7 +194,7 @@ public function offsetSet($key, $value) /** * Not supported. * - * @see http://php.net/arrayaccess.offsetunset + * @see https://php.net/arrayaccess.offsetunset * @param mixed $key * @throws BadMethodCallException * @return void diff --git a/src/Model/CollectionInfoCommandIterator.php b/src/Model/CollectionInfoCommandIterator.php index 4324c1338..316b67fb0 100644 --- a/src/Model/CollectionInfoCommandIterator.php +++ b/src/Model/CollectionInfoCommandIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -30,7 +30,7 @@ * @internal * @see \MongoDB\Database::listCollections() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst - * @see http://mongodb.com/docs/manual/reference/command/listCollections/ + * @see https://mongodb.com/docs/manual/reference/command/listCollections/ */ class CollectionInfoCommandIterator extends IteratorIterator implements CollectionInfoIterator { @@ -51,7 +51,7 @@ public function __construct(Traversable $iterator, $databaseName = null) * Return the current element as a CollectionInfo instance. * * @see CollectionInfoIterator::current() - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return CollectionInfo */ #[ReturnTypeWillChange] diff --git a/src/Model/CollectionInfoIterator.php b/src/Model/CollectionInfoIterator.php index 70d3bba22..aa6cb3afb 100644 --- a/src/Model/CollectionInfoIterator.php +++ b/src/Model/CollectionInfoIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Model/DatabaseInfo.php b/src/Model/DatabaseInfo.php index ae651a853..3f6326f7b 100644 --- a/src/Model/DatabaseInfo.php +++ b/src/Model/DatabaseInfo.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -31,7 +31,7 @@ * * @api * @see \MongoDB\Client::listDatabases() - * @see http://mongodb.com/docs/manual/reference/command/listDatabases/ + * @see https://mongodb.com/docs/manual/reference/command/listDatabases/ */ class DatabaseInfo implements ArrayAccess { @@ -49,7 +49,7 @@ public function __construct(array $info) /** * Return the database info as an array. * - * @see http://php.net/oop5.magic#language.oop5.magic.debuginfo + * @see https://php.net/oop5.magic#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -91,7 +91,7 @@ public function isEmpty() /** * Check whether a field exists in the database information. * - * @see http://php.net/arrayaccess.offsetexists + * @see https://php.net/arrayaccess.offsetexists * @param mixed $key * @return boolean */ @@ -104,7 +104,7 @@ public function offsetExists($key) /** * Return the field's value from the database information. * - * @see http://php.net/arrayaccess.offsetget + * @see https://php.net/arrayaccess.offsetget * @param mixed $key * @return mixed */ @@ -117,7 +117,7 @@ public function offsetGet($key) /** * Not supported. * - * @see http://php.net/arrayaccess.offsetset + * @see https://php.net/arrayaccess.offsetset * @param mixed $key * @param mixed $value * @throws BadMethodCallException @@ -132,7 +132,7 @@ public function offsetSet($key, $value) /** * Not supported. * - * @see http://php.net/arrayaccess.offsetunset + * @see https://php.net/arrayaccess.offsetunset * @param mixed $key * @throws BadMethodCallException * @return void diff --git a/src/Model/DatabaseInfoIterator.php b/src/Model/DatabaseInfoIterator.php index 9391916b4..cb6135750 100644 --- a/src/Model/DatabaseInfoIterator.php +++ b/src/Model/DatabaseInfoIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Model/DatabaseInfoLegacyIterator.php b/src/Model/DatabaseInfoLegacyIterator.php index 616bcca64..c6f5f0842 100644 --- a/src/Model/DatabaseInfoLegacyIterator.php +++ b/src/Model/DatabaseInfoLegacyIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -32,7 +32,7 @@ * * @internal * @see \MongoDB\Client::listDatabases() - * @see http://mongodb.com/docs/manual/reference/command/listDatabases/ + * @see https://mongodb.com/docs/manual/reference/command/listDatabases/ */ class DatabaseInfoLegacyIterator implements DatabaseInfoIterator { @@ -51,7 +51,7 @@ public function __construct(array $databases) * Return the current element as a DatabaseInfo instance. * * @see DatabaseInfoIterator::current() - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return DatabaseInfo */ public function current() @@ -62,7 +62,7 @@ public function current() /** * Return the key of the current element. * - * @see http://php.net/iterator.key + * @see https://php.net/iterator.key * @return integer */ #[ReturnTypeWillChange] @@ -74,7 +74,7 @@ public function key() /** * Move forward to next element. * - * @see http://php.net/iterator.next + * @see https://php.net/iterator.next * @return void */ #[ReturnTypeWillChange] @@ -86,7 +86,7 @@ public function next() /** * Rewind the Iterator to the first element. * - * @see http://php.net/iterator.rewind + * @see https://php.net/iterator.rewind * @return void */ #[ReturnTypeWillChange] @@ -98,7 +98,7 @@ public function rewind() /** * Checks if current position is valid. * - * @see http://php.net/iterator.valid + * @see https://php.net/iterator.valid * @return boolean */ #[ReturnTypeWillChange] diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php index 968701422..5e49568d2 100644 --- a/src/Model/IndexInfo.php +++ b/src/Model/IndexInfo.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -37,7 +37,7 @@ * @api * @see \MongoDB\Collection::listIndexes() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst - * @see http://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ + * @see https://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ */ class IndexInfo implements ArrayAccess { @@ -55,7 +55,7 @@ public function __construct(array $info) /** * Return the collection info as an array. * - * @see http://php.net/oop5.magic#language.oop5.magic.debuginfo + * @see https://php.net/oop5.magic#language.oop5.magic.debuginfo * @return array */ public function __debugInfo() @@ -136,7 +136,7 @@ public function isGeoHaystack() /** * Return whether this is a sparse index. * - * @see http://mongodb.com/docs/manual/core/index-sparse/ + * @see https://mongodb.com/docs/manual/core/index-sparse/ * @return boolean */ public function isSparse() @@ -157,7 +157,7 @@ public function isText() /** * Return whether this is a TTL index. * - * @see http://mongodb.com/docs/manual/core/index-ttl/ + * @see https://mongodb.com/docs/manual/core/index-ttl/ * @return boolean */ public function isTtl() @@ -168,7 +168,7 @@ public function isTtl() /** * Return whether this is a unique index. * - * @see http://mongodb.com/docs/manual/core/index-unique/ + * @see https://mongodb.com/docs/manual/core/index-unique/ * @return boolean */ public function isUnique() @@ -179,7 +179,7 @@ public function isUnique() /** * Check whether a field exists in the index information. * - * @see http://php.net/arrayaccess.offsetexists + * @see https://php.net/arrayaccess.offsetexists * @param mixed $key * @return boolean */ @@ -196,7 +196,7 @@ public function offsetExists($key) * that index fields be made accessible under their original names. It may * also be used to access fields that do not have a helper method. * - * @see http://php.net/arrayaccess.offsetget + * @see https://php.net/arrayaccess.offsetget * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst#getting-full-index-information * @param mixed $key * @return mixed @@ -210,7 +210,7 @@ public function offsetGet($key) /** * Not supported. * - * @see http://php.net/arrayaccess.offsetset + * @see https://php.net/arrayaccess.offsetset * @param mixed $key * @param mixed $value * @throws BadMethodCallException @@ -225,7 +225,7 @@ public function offsetSet($key, $value) /** * Not supported. * - * @see http://php.net/arrayaccess.offsetunset + * @see https://php.net/arrayaccess.offsetunset * @param mixed $key * @throws BadMethodCallException * @return void diff --git a/src/Model/IndexInfoIterator.php b/src/Model/IndexInfoIterator.php index 7ddcab175..342fac6a8 100644 --- a/src/Model/IndexInfoIterator.php +++ b/src/Model/IndexInfoIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Model/IndexInfoIteratorIterator.php b/src/Model/IndexInfoIteratorIterator.php index 2410e805b..fcdcbf041 100644 --- a/src/Model/IndexInfoIteratorIterator.php +++ b/src/Model/IndexInfoIteratorIterator.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -33,8 +33,8 @@ * @internal * @see \MongoDB\Collection::listIndexes() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst - * @see http://mongodb.com/docs/manual/reference/command/listIndexes/ - * @see http://mongodb.com/docs/manual/reference/system-collections/ + * @see https://mongodb.com/docs/manual/reference/command/listIndexes/ + * @see https://mongodb.com/docs/manual/reference/system-collections/ */ class IndexInfoIteratorIterator extends IteratorIterator implements IndexInfoIterator { @@ -55,7 +55,7 @@ public function __construct(Traversable $iterator, $ns = null) * Return the current element as an IndexInfo instance. * * @see IndexInfoIterator::current() - * @see http://php.net/iterator.current + * @see https://php.net/iterator.current * @return IndexInfo */ #[ReturnTypeWillChange] diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php index 7ed36cc04..584d8f912 100644 --- a/src/Model/IndexInput.php +++ b/src/Model/IndexInput.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -36,7 +36,7 @@ * @internal * @see \MongoDB\Collection::createIndexes() * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst - * @see http://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ + * @see https://mongodb.com/docs/manual/reference/method/db.collection.createIndex/ */ class IndexInput implements Serializable { @@ -88,7 +88,7 @@ public function __toString() * Serialize the index information to BSON for index creation. * * @see \MongoDB\Collection::createIndexes() - * @see http://php.net/mongodb-bson-serializable.bsonserialize + * @see https://php.net/mongodb-bson-serializable.bsonserialize * @return array */ public function bsonSerialize() diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 742540232..1573c5d94 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -47,7 +47,7 @@ * * @api * @see \MongoDB\Collection::aggregate() - * @see http://mongodb.com/docs/manual/reference/command/aggregate/ + * @see https://mongodb.com/docs/manual/reference/command/aggregate/ */ class Aggregate implements Executable, Explainable { @@ -369,9 +369,9 @@ private function createCommandOptions(): array /** * Execute the aggregate command using the appropriate Server method. * - * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php - * @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php - * @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php */ private function executeCommand(Server $server, Command $command): Cursor { diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index b37124e66..dd898cc2b 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -337,7 +337,7 @@ public function execute(Server $server) /** * Create options for constructing the bulk write. * - * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php * @return array */ private function createBulkWriteOptions() @@ -354,7 +354,7 @@ private function createBulkWriteOptions() /** * Create options for executing the bulk write. * - * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php + * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ private function createExecuteOptions() diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 28f3fbd00..4d76f0a78 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -39,7 +39,7 @@ * * @api * @see \MongoDB\Collection::count() - * @see http://mongodb.com/docs/manual/reference/command/count/ + * @see https://mongodb.com/docs/manual/reference/command/count/ */ class Count implements Executable, Explainable { @@ -207,7 +207,7 @@ private function createCommandDocument() /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php * @return array */ private function createOptions() diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index df6be9f28..6771d8d95 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index bfc11fb04..de771399b 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -39,7 +39,7 @@ * * @api * @see \MongoDB\Database::createCollection() - * @see http://mongodb.com/docs/manual/reference/command/create/ + * @see https://mongodb.com/docs/manual/reference/command/create/ */ class CreateCollection implements Executable { @@ -112,7 +112,7 @@ class CreateCollection implements Executable * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * - * @see http://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb + * @see https://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb * @see https://mongodb.com/docs/manual/core/schema-validation/ * @param string $databaseName Database name * @param string $collectionName Collection name @@ -248,7 +248,7 @@ private function createCommand() /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php index 4d96e6e34..5778960c9 100644 --- a/src/Operation/CreateIndexes.php +++ b/src/Operation/CreateIndexes.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -39,7 +39,7 @@ * @api * @see \MongoDB\Collection::createIndex() * @see \MongoDB\Collection::createIndexes() - * @see http://mongodb.com/docs/manual/reference/command/createIndexes/ + * @see https://mongodb.com/docs/manual/reference/command/createIndexes/ */ class CreateIndexes implements Executable { @@ -153,7 +153,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php index ffe9f3016..317abc658 100644 --- a/src/Operation/DatabaseCommand.php +++ b/src/Operation/DatabaseCommand.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -109,7 +109,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 9bb70bfb9..fb60d09a5 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -39,7 +39,7 @@ * classes. * * @internal - * @see http://mongodb.com/docs/manual/reference/command/delete/ + * @see https://mongodb.com/docs/manual/reference/command/delete/ */ class Delete implements Executable, Explainable { @@ -202,7 +202,7 @@ private function createDeleteOptions() /** * Create options for executing the bulk write. * - * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php + * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ private function createExecuteOptions() diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index 52c4d52c9..0e43ff889 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -28,7 +28,7 @@ * * @api * @see \MongoDB\Collection::deleteOne() - * @see http://mongodb.com/docs/manual/reference/command/delete/ + * @see https://mongodb.com/docs/manual/reference/command/delete/ */ class DeleteMany implements Executable, Explainable { diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index 941cce91c..1f797b0c9 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -28,7 +28,7 @@ * * @api * @see \MongoDB\Collection::deleteOne() - * @see http://mongodb.com/docs/manual/reference/command/delete/ + * @see https://mongodb.com/docs/manual/reference/command/delete/ */ class DeleteOne implements Executable, Explainable { diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index a04e1b989..aefee694c 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -38,7 +38,7 @@ * * @api * @see \MongoDB\Collection::distinct() - * @see http://mongodb.com/docs/manual/reference/command/distinct/ + * @see https://mongodb.com/docs/manual/reference/command/distinct/ */ class Distinct implements Executable, Explainable { @@ -197,7 +197,7 @@ private function createCommandDocument() /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php * @return array */ private function createOptions() diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 3ec109a66..2eb77890c 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -34,7 +34,7 @@ * @api * @see \MongoDB\Collection::drop() * @see \MongoDB\Database::dropCollection() - * @see http://mongodb.com/docs/manual/reference/command/drop/ + * @see https://mongodb.com/docs/manual/reference/command/drop/ */ class DropCollection implements Executable { @@ -131,7 +131,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php index f76fb8a94..6d7e61713 100644 --- a/src/Operation/DropDatabase.php +++ b/src/Operation/DropDatabase.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -33,7 +33,7 @@ * @api * @see \MongoDB\Client::dropDatabase() * @see \MongoDB\Database::drop() - * @see http://mongodb.com/docs/manual/reference/command/dropDatabase/ + * @see https://mongodb.com/docs/manual/reference/command/dropDatabase/ */ class DropDatabase implements Executable { @@ -104,7 +104,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php index ddb0f5468..170cf9875 100644 --- a/src/Operation/DropIndexes.php +++ b/src/Operation/DropIndexes.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -34,7 +34,7 @@ * * @api * @see \MongoDB\Collection::dropIndexes() - * @see http://mongodb.com/docs/manual/reference/command/dropIndexes/ + * @see https://mongodb.com/docs/manual/reference/command/dropIndexes/ */ class DropIndexes implements Executable { @@ -152,7 +152,7 @@ private function createCommand() /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index 1aed13de3..53f810f64 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -36,7 +36,7 @@ * * @api * @see \MongoDB\Collection::estimatedDocumentCount() - * @see http://mongodb.com/docs/manual/reference/command/count/ + * @see https://mongodb.com/docs/manual/reference/command/count/ */ class EstimatedDocumentCount implements Executable, Explainable { diff --git a/src/Operation/Executable.php b/src/Operation/Executable.php index 568badbe4..b71b20ba6 100644 --- a/src/Operation/Executable.php +++ b/src/Operation/Executable.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php index 8750cdbf8..862e9a152 100644 --- a/src/Operation/Explain.php +++ b/src/Operation/Explain.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -35,7 +35,7 @@ * * @api * @see \MongoDB\Collection::explain() - * @see http://mongodb.com/docs/manual/reference/command/explain/ + * @see https://mongodb.com/docs/manual/reference/command/explain/ */ class Explain implements Executable { @@ -130,7 +130,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/Explainable.php b/src/Operation/Explainable.php index 315c8c4d4..973495235 100644 --- a/src/Operation/Explainable.php +++ b/src/Operation/Explainable.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Operation/Find.php b/src/Operation/Find.php index b84c5bb49..f3bff9e02 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -41,8 +41,8 @@ * * @api * @see \MongoDB\Collection::find() - * @see http://mongodb.com/docs/manual/tutorial/query-documents/ - * @see http://mongodb.com/docs/manual/reference/operator/query-modifier/ + * @see https://mongodb.com/docs/manual/tutorial/query-documents/ + * @see https://mongodb.com/docs/manual/reference/operator/query-modifier/ */ class Find implements Executable, Explainable { @@ -373,7 +373,7 @@ private function createCommandDocument(): array /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executequery.php + * @see https://php.net/manual/en/mongodb-driver-server.executequery.php * @return array */ private function createExecuteOptions() diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 5c6a9f240..07ae1ea7d 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -44,7 +44,7 @@ * FindOneAndUpdate operation classes. * * @internal - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindAndModify implements Executable, Explainable { @@ -299,7 +299,7 @@ private function createCommandDocument() /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index aff680733..0193b389e 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -29,8 +29,8 @@ * * @api * @see \MongoDB\Collection::findOne() - * @see http://mongodb.com/docs/manual/tutorial/query-documents/ - * @see http://mongodb.com/docs/manual/reference/operator/query-modifier/ + * @see https://mongodb.com/docs/manual/tutorial/query-documents/ + * @see https://mongodb.com/docs/manual/reference/operator/query-modifier/ */ class FindOne implements Executable, Explainable { diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index be764b740..4c31977d3 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -30,7 +30,7 @@ * * @api * @see \MongoDB\Collection::findOneAndDelete() - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindOneAndDelete implements Executable, Explainable { diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 076907d9d..215d5536f 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -32,7 +32,7 @@ * * @api * @see \MongoDB\Collection::findOneAndReplace() - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindOneAndReplace implements Executable, Explainable { diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index f37f2d1ff..1f09e1547 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::findOneAndUpdate() - * @see http://mongodb.com/docs/manual/reference/command/findAndModify/ + * @see https://mongodb.com/docs/manual/reference/command/findAndModify/ */ class FindOneAndUpdate implements Executable, Explainable { diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index 15d1de8ed..7633905fe 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -36,7 +36,7 @@ * * @api * @see \MongoDB\Collection::insertMany() - * @see http://mongodb.com/docs/manual/reference/command/insert/ + * @see https://mongodb.com/docs/manual/reference/command/insert/ */ class InsertMany implements Executable { @@ -157,7 +157,7 @@ public function execute(Server $server) /** * Create options for constructing the bulk write. * - * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php * @return array */ private function createBulkWriteOptions() @@ -174,7 +174,7 @@ private function createBulkWriteOptions() /** * Create options for executing the bulk write. * - * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php + * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ private function createExecuteOptions() diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index 4a330a692..39e986683 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -35,7 +35,7 @@ * * @api * @see \MongoDB\Collection::insertOne() - * @see http://mongodb.com/docs/manual/reference/command/insert/ + * @see https://mongodb.com/docs/manual/reference/command/insert/ */ class InsertOne implements Executable { @@ -128,7 +128,7 @@ public function execute(Server $server) /** * Create options for constructing the bulk write. * - * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php * @return array */ private function createBulkWriteOptions() @@ -145,7 +145,7 @@ private function createBulkWriteOptions() /** * Create options for executing the bulk write. * - * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php + * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ private function createExecuteOptions() diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index e5b77e856..c5fc568ff 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -29,7 +29,7 @@ * * @api * @see \MongoDB\Database::listCollectionNames() - * @see http://mongodb.com/docs/manual/reference/command/listCollections/ + * @see https://mongodb.com/docs/manual/reference/command/listCollections/ */ class ListCollectionNames implements Executable { diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php index 8212ff26d..f346263e3 100644 --- a/src/Operation/ListCollections.php +++ b/src/Operation/ListCollections.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -29,7 +29,7 @@ * * @api * @see \MongoDB\Database::listCollections() - * @see http://mongodb.com/docs/manual/reference/command/listCollections/ + * @see https://mongodb.com/docs/manual/reference/command/listCollections/ */ class ListCollections implements Executable { diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php index 8f82b257c..2c15ca97e 100644 --- a/src/Operation/ListDatabaseNames.php +++ b/src/Operation/ListDatabaseNames.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Operation/ListDatabases.php b/src/Operation/ListDatabases.php index 8e74ba159..abfcb2a0a 100644 --- a/src/Operation/ListDatabases.php +++ b/src/Operation/ListDatabases.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index 2574208c6..213b7dd03 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -35,7 +35,7 @@ * * @api * @see \MongoDB\Collection::listIndexes() - * @see http://mongodb.com/docs/manual/reference/command/listIndexes/ + * @see https://mongodb.com/docs/manual/reference/command/listIndexes/ */ class ListIndexes implements Executable { @@ -103,7 +103,7 @@ public function execute(Server $server) * Note: read preference is intentionally omitted, as the spec requires that * the command be executed on the primary. * - * @see http://php.net/manual/en/mongodb-driver-server.executecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index e7a928812..46827b1a9 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -391,8 +391,8 @@ private function createGetIteratorCallable(stdClass $result, Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executereadcommand.php - * @see http://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php * @param boolean $hasOutputCollection * @return array */ diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php index 5ffe476dc..e6e16961d 100644 --- a/src/Operation/ModifyCollection.php +++ b/src/Operation/ModifyCollection.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -32,7 +32,7 @@ * * @api * @see \MongoDB\Database::modifyCollection() - * @see http://mongodb.com/docs/manual/reference/command/collMod/ + * @see https://mongodb.com/docs/manual/reference/command/collMod/ */ class ModifyCollection implements Executable { @@ -116,7 +116,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php index 14402e5a3..1a02cf40f 100644 --- a/src/Operation/RenameCollection.php +++ b/src/Operation/RenameCollection.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -133,7 +133,7 @@ public function execute(Server $server) /** * Create options for executing the command. * - * @see http://php.net/manual/en/mongodb-driver-server.executewritecommand.php + * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php * @return array */ private function createOptions() diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index 40921e794..6285bc738 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::replaceOne() - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ */ class ReplaceOne implements Executable { diff --git a/src/Operation/Update.php b/src/Operation/Update.php index cbbb88f2f..3081591f0 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -42,7 +42,7 @@ * operation classes. * * @internal - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ */ class Update implements Executable, Explainable { @@ -227,7 +227,7 @@ public function getCommandDocument(Server $server) /** * Create options for constructing the bulk write. * - * @see https://www.php.net/manual/en/mongodb-driver-bulkwrite.construct.php + * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php * @return array */ private function createBulkWriteOptions() @@ -244,7 +244,7 @@ private function createBulkWriteOptions() /** * Create options for executing the bulk write. * - * @see http://php.net/manual/en/mongodb-driver-server.executebulkwrite.php + * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php * @return array */ private function createExecuteOptions() diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index d8fb9ea13..f63d4cbab 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::updateMany() - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ */ class UpdateMany implements Executable, Explainable { diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index b1ead711a..699516595 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -6,7 +6,7 @@ * 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 + * https://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, @@ -33,7 +33,7 @@ * * @api * @see \MongoDB\Collection::updateOne() - * @see http://mongodb.com/docs/manual/reference/command/update/ + * @see https://mongodb.com/docs/manual/reference/command/update/ */ class UpdateOne implements Executable, Explainable { diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index db752d99b..62d7ff83c 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/UpdateResult.php b/src/UpdateResult.php index 314dfc64d..de75afcbc 100644 --- a/src/UpdateResult.php +++ b/src/UpdateResult.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/src/functions.php b/src/functions.php index c838d3075..37b2edc6d 100644 --- a/src/functions.php +++ b/src/functions.php @@ -6,7 +6,7 @@ * 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 + * https://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, diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index 6f44e72e3..428ead145 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -156,7 +156,7 @@ public static function fromTransactions(array $expectedEvents) /** * Not used. * - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ public function commandFailed(CommandFailedEvent $event): void { @@ -170,7 +170,7 @@ public function commandFailed(CommandFailedEvent $event): void /** * Tracks outgoing commands for spec test APM assertions. * - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ public function commandStarted(CommandStartedEvent $event): void { @@ -184,7 +184,7 @@ public function commandStarted(CommandStartedEvent $event): void /** * Not used. * - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ public function commandSucceeded(CommandSucceededEvent $event): void { diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php index 9499130d4..1c05b23e0 100644 --- a/tests/UnifiedSpecTests/EntityMap.php +++ b/tests/UnifiedSpecTests/EntityMap.php @@ -57,7 +57,7 @@ public function __destruct() } /** - * @see http://php.net/arrayaccess.offsetexists + * @see https://php.net/arrayaccess.offsetexists */ public function offsetExists($id): bool { @@ -67,7 +67,7 @@ public function offsetExists($id): bool } /** - * @see http://php.net/arrayaccess.offsetget + * @see https://php.net/arrayaccess.offsetget * @return mixed */ #[ReturnTypeWillChange] @@ -80,7 +80,7 @@ public function offsetGet($id) } /** - * @see http://php.net/arrayaccess.offsetset + * @see https://php.net/arrayaccess.offsetset */ public function offsetSet($id, $value): void { @@ -88,7 +88,7 @@ public function offsetSet($id, $value): void } /** - * @see http://php.net/arrayaccess.offsetunset + * @see https://php.net/arrayaccess.offsetunset */ public function offsetUnset($id): void { diff --git a/tests/UnifiedSpecTests/EventCollector.php b/tests/UnifiedSpecTests/EventCollector.php index 4259ab182..1da92832c 100644 --- a/tests/UnifiedSpecTests/EventCollector.php +++ b/tests/UnifiedSpecTests/EventCollector.php @@ -81,7 +81,7 @@ public function __construct(BSONArray $eventList, array $collectEvents, string $ } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ public function commandFailed(CommandFailedEvent $event): void { @@ -89,7 +89,7 @@ public function commandFailed(CommandFailedEvent $event): void } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ public function commandStarted(CommandStartedEvent $event): void { @@ -97,7 +97,7 @@ public function commandStarted(CommandStartedEvent $event): void } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ public function commandSucceeded(CommandSucceededEvent $event): void { diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index 1cd47e968..3404ac2a4 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -150,7 +150,7 @@ public function __construct(array $observeEvents, array $ignoreCommands, bool $o } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ public function commandFailed(CommandFailedEvent $event): void { @@ -158,7 +158,7 @@ public function commandFailed(CommandFailedEvent $event): void } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ public function commandStarted(CommandStartedEvent $event): void { @@ -166,7 +166,7 @@ public function commandStarted(CommandStartedEvent $event): void } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ public function commandSucceeded(CommandSucceededEvent $event): void { diff --git a/tests/UnifiedSpecTests/FailPointObserver.php b/tests/UnifiedSpecTests/FailPointObserver.php index c38854838..76d3b9633 100644 --- a/tests/UnifiedSpecTests/FailPointObserver.php +++ b/tests/UnifiedSpecTests/FailPointObserver.php @@ -17,14 +17,14 @@ class FailPointObserver implements CommandSubscriber private $failPointsAndServers = []; /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */ public function commandFailed(CommandFailedEvent $event): void { } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */ public function commandStarted(CommandStartedEvent $event): void { @@ -42,7 +42,7 @@ public function commandStarted(CommandStartedEvent $event): void } /** - * @see https://www.php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php + * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */ public function commandSucceeded(CommandSucceededEvent $event): void { diff --git a/tests/UnifiedSpecTests/UnifiedTestCase.php b/tests/UnifiedSpecTests/UnifiedTestCase.php index e98db65c0..ced1adec0 100644 --- a/tests/UnifiedSpecTests/UnifiedTestCase.php +++ b/tests/UnifiedSpecTests/UnifiedTestCase.php @@ -55,8 +55,8 @@ private function __construct(stdClass $test, string $schemaVersion, ?array $runO * This allows the UnifiedTest object to be used directly with the argument * unpacking operator (i.e. "..."). * - * @see https://www.php.net/manual/en/iteratoraggregate.getiterator.php - * @see https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list + * @see https://php.net/manual/en/iteratoraggregate.getiterator.php + * @see https://php.net/manual/en/functions.arguments.php#functions.variable-arg-list */ public function getIterator(): Traversable { From 8c788f10a4954fcb85ab78cdece3f9bf74d1e1b8 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Fri, 1 Apr 2022 00:19:34 +0300 Subject: [PATCH 123/321] PHPLIB-808: Leave fullDocument change stream option unset by default (#901) array_key_exists function is used to avoid case when array field "fullDocument" with NULL value is passed from input (there is already exists an incorrect NULL-value input data test in MongoDB\Tests\Operation\WatchTest:55) --- src/Operation/Watch.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 62d7ff83c..3b4927ce3 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -34,6 +34,7 @@ use MongoDB\Model\ChangeStreamIterator; use function array_intersect_key; +use function array_key_exists; use function array_unshift; use function count; use function is_array; @@ -173,11 +174,10 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } $options += [ - 'fullDocument' => self::FULL_DOCUMENT_DEFAULT, 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), ]; - if (! is_string($options['fullDocument'])) { + if (array_key_exists('fullDocument', $options) && ! is_string($options['fullDocument'])) { throw InvalidArgumentException::invalidType('"fullDocument" option', $options['fullDocument'], 'string'); } From a5c1bf827569565667edc5ecbb71ce7c2cf6ddde Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Fri, 1 Apr 2022 00:55:34 +0300 Subject: [PATCH 124/321] PHPLIB-658: optional new and upsert fields for findAndModify commands (#904) * Making arguments "returnDocument", "upsert" and "new" optional * Making an extra check for input value of "returnDocument" argument to maintain test input data, which contains NULL value of this field. * For fields "new" and "upsert" the same extra check is added to keep the same behavior of FindAndModify constructor verification stage if NULL value would be passed, despite the test data doesn't currently contain such cases. --- src/Operation/FindAndModify.php | 20 +++++++++++--------- src/Operation/FindOneAndReplace.php | 13 ++++++------- src/Operation/FindOneAndUpdate.php | 13 ++++++------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 07ae1ea7d..eb0aa3169 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -26,6 +26,7 @@ use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; +use function array_key_exists; use function current; use function is_array; use function is_bool; @@ -121,11 +122,7 @@ class FindAndModify implements Executable, Explainable */ public function __construct($databaseName, $collectionName, array $options) { - $options += [ - 'new' => false, - 'remove' => false, - 'upsert' => false, - ]; + $options += ['remove' => false]; if (isset($options['arrayFilters']) && ! is_array($options['arrayFilters'])) { throw InvalidArgumentException::invalidType('"arrayFilters" option', $options['arrayFilters'], 'array'); @@ -151,7 +148,7 @@ public function __construct($databaseName, $collectionName, array $options) throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } - if (! is_bool($options['new'])) { + if (array_key_exists('new', $options) && ! is_bool($options['new'])) { throw InvalidArgumentException::invalidType('"new" option', $options['new'], 'boolean'); } @@ -183,7 +180,7 @@ public function __construct($databaseName, $collectionName, array $options) throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } - if (! is_bool($options['upsert'])) { + if (array_key_exists('upsert', $options) && ! is_bool($options['upsert'])) { throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); } @@ -271,8 +268,13 @@ private function createCommandDocument() if ($this->options['remove']) { $cmd['remove'] = true; } else { - $cmd['new'] = $this->options['new']; - $cmd['upsert'] = $this->options['upsert']; + if (isset($this->options['new'])) { + $cmd['new'] = $this->options['new']; + } + + if (isset($this->options['upsert'])) { + $cmd['upsert'] = $this->options['upsert']; + } } foreach (['collation', 'fields', 'query', 'sort'] as $option) { diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 215d5536f..999a3eef5 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -22,6 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; +use function array_key_exists; use function is_array; use function is_integer; use function is_object; @@ -104,20 +105,16 @@ public function __construct($databaseName, $collectionName, $filter, $replacemen throw new InvalidArgumentException('First key in $replacement argument is an update operator'); } - $options += [ - 'returnDocument' => self::RETURN_DOCUMENT_BEFORE, - 'upsert' => false, - ]; - if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); } - if (! is_integer($options['returnDocument'])) { + if (array_key_exists('returnDocument', $options) && ! is_integer($options['returnDocument'])) { throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer'); } if ( + isset($options['returnDocument']) && $options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE ) { @@ -128,7 +125,9 @@ public function __construct($databaseName, $collectionName, $filter, $replacemen $options['fields'] = $options['projection']; } - $options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER; + if (isset($options['returnDocument'])) { + $options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER; + } unset($options['projection'], $options['returnDocument']); diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index 1f09e1547..5cbf1ad33 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -22,6 +22,7 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\UnsupportedException; +use function array_key_exists; use function is_array; use function is_integer; use function is_object; @@ -108,20 +109,16 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline'); } - $options += [ - 'returnDocument' => self::RETURN_DOCUMENT_BEFORE, - 'upsert' => false, - ]; - if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) { throw InvalidArgumentException::invalidType('"projection" option', $options['projection'], 'array or object'); } - if (! is_integer($options['returnDocument'])) { + if (array_key_exists('returnDocument', $options) && ! is_integer($options['returnDocument'])) { throw InvalidArgumentException::invalidType('"returnDocument" option', $options['returnDocument'], 'integer'); } if ( + isset($options['returnDocument']) && $options['returnDocument'] !== self::RETURN_DOCUMENT_AFTER && $options['returnDocument'] !== self::RETURN_DOCUMENT_BEFORE ) { @@ -132,7 +129,9 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar $options['fields'] = $options['projection']; } - $options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER; + if (isset($options['returnDocument'])) { + $options['new'] = $options['returnDocument'] === self::RETURN_DOCUMENT_AFTER; + } unset($options['projection'], $options['returnDocument']); From 3370bfce96116ced2b2530da61b61573b95360cb Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Fri, 1 Apr 2022 00:59:39 +0300 Subject: [PATCH 125/321] PHPLIB-761: Disable client persistence when creating clients in test runners (#905) Replacing old random ids for new clients with special flag "disableClientPersistence" to maintain tests same behavior. --- tests/SpecTests/Context.php | 9 +++------ tests/UnifiedSpecTests/Context.php | 6 ++---- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 286c03b65..1521bd78e 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -15,7 +15,6 @@ use function array_keys; use function getenv; use function implode; -use function mt_rand; use function uniqid; /** @@ -239,12 +238,10 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - /* Transaction spec tests expect a new client for each test so that - * txnNumber values are deterministic. Append a random option to avoid - * re-using a previously persisted libmongoc client object. */ - $clientOptions += ['p' => mt_rand()]; + // Transaction spec tests expect a new client for each test so that txnNumber values are deterministic. + $driverOptions = ['disableClientPersistence' => true]; - $o->client = FunctionalTestCase::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); + $o->client = FunctionalTestCase::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions, $driverOptions); $session0Options = isset($test->sessionOptions->session0) ? (array) $test->sessionOptions->session0 : []; $session1Options = isset($test->sessionOptions->session1) ? (array) $test->sessionOptions->session1 : []; diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 9b08a4fee..c47219988 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -294,10 +294,8 @@ private function createClient(string $id, stdClass $o): void } } - /* TODO: Remove this once PHPC-1645 is implemented. Each client needs - * its own libmongoc client to facilitate txnNumber assertions. */ - static $i = 0; - $driverOptions = isset($observeEvents) ? ['i' => $i++] : []; + // Transaction tests expect a new client for each test so that txnNumber values are deterministic. + $driverOptions = isset($observeEvents) ? ['disableClientPersistence' => true] : []; if ($serverApi !== null) { assertIsObject($serverApi); From bc60323ad780f514950781005fb90a0e4d939506 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 6 Apr 2022 14:14:10 -0400 Subject: [PATCH 126/321] PHPLIB-831: Allow $$exists within $$unsetOrMatches (#909) --- tests/UnifiedSpecTests/Constraint/Matches.php | 15 ++++++++++++++ .../Constraint/MatchesTest.php | 20 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/UnifiedSpecTests/Constraint/Matches.php b/tests/UnifiedSpecTests/Constraint/Matches.php index 4704519cf..aebd72510 100644 --- a/tests/UnifiedSpecTests/Constraint/Matches.php +++ b/tests/UnifiedSpecTests/Constraint/Matches.php @@ -24,6 +24,7 @@ use function is_float; use function is_int; use function is_object; +use function ltrim; use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertMatchesRegularExpression; @@ -37,6 +38,7 @@ use function range; use function sprintf; use function strpos; +use function strrchr; use const PHP_INT_SIZE; @@ -240,6 +242,19 @@ private function assertMatchesOperator(BSONDocument $operator, $actual, string $ { $name = self::getOperatorName($operator); + if ($name === '$$exists') { + assertIsBool($operator['$$exists'], '$$exists requires bool'); + + /* If we get to this point, the field itself must already exist so + * we need only fail if $$exists is false. */ + if ($operator['$$exists'] === false) { + $key = ltrim(strrchr($keyPath, '.'), '.'); + self::failAt(sprintf('$actual has unexpected key "%s"', $key), $keyPath); + } + + return; + } + if ($name === '$$type') { assertThat( $operator['$$type'], diff --git a/tests/UnifiedSpecTests/Constraint/MatchesTest.php b/tests/UnifiedSpecTests/Constraint/MatchesTest.php index 8f0adfd0f..50b13a4de 100644 --- a/tests/UnifiedSpecTests/Constraint/MatchesTest.php +++ b/tests/UnifiedSpecTests/Constraint/MatchesTest.php @@ -119,6 +119,26 @@ public function testOperatorUnsetOrMatches(): void $this->assertResult(false, $c, ['x' => ['y' => 1, 'z' => 2]], 'value does not match (embedded)'); } + public function testOperatorUnsetOrMatchesWithNestedOperator(): void + { + // Nested $$unsetOrMatches is redundant, but should behave the same as if it was omitted + $c = new Matches(['x' => ['$$unsetOrMatches' => ['$$unsetOrMatches' => ['y' => 1]]]]); + $this->assertResult(true, $c, new stdClass(), 'missing value is considered unset (embedded)'); + $this->assertResult(false, $c, ['x' => null], 'null value is not considered unset (embedded)'); + $this->assertResult(true, $c, ['x' => ['y' => 1]], 'value matches (embedded)'); + $this->assertResult(false, $c, ['x' => ['y' => 1, 'z' => 2]], 'value does not match (embedded)'); + + $c = new Matches(['x' => ['$$unsetOrMatches' => ['$$exists' => true]]]); + $this->assertResult(true, $c, new stdClass(), 'missing value is considered unset (embedded)'); + $this->assertResult(true, $c, ['x' => null], 'null value is not considered unset (embedded)'); + $this->assertResult(true, $c, ['x' => ['y' => 1]], 'non-null value is not considered unset (embedded)'); + + $c = new Matches(['x' => ['$$unsetOrMatches' => ['$$exists' => false]]]); + $this->assertResult(true, $c, new stdClass(), 'missing value is considered unset (embedded)'); + $this->assertResult(false, $c, ['x' => null], 'null value is not considered unset (embedded)'); + $this->assertResult(false, $c, ['x' => ['y' => 1]], 'non-null value is not considered unset (embedded)'); + } + public function testOperatorSessionLsid(): void { $session = $this->manager->startSession(); From aefff4c654afc6b6d671aae2c05b05441dbb4012 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Tue, 12 Apr 2022 16:54:19 +0300 Subject: [PATCH 127/321] PHPLIB-835: fix CSFLE "Custom Endpoint Test" Case 5 (#912) --- tests/SpecTests/ClientSideEncryptionSpecTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 9c34d61bf..2babb6164 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -724,7 +724,6 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio yield 'Test 5' => [ static function (self $test, ClientEncryption $clientEncryption, ClientEncryption $clientEncryptionInvalid) use ($awsMasterKey): void { $test->expectException(RuntimeException::class); - $test->expectExceptionMessageMatches('#us-east-1#'); $clientEncryption->createDataKey('aws', ['masterKey' => $awsMasterKey + ['endpoint' => 'kms.us-east-2.amazonaws.com']]); }, ]; From dfd77e6d88c9c0f97bf006d5c36c685f3a901b93 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 14 Apr 2022 09:48:28 -0400 Subject: [PATCH 128/321] PHPLIB-841: Tests for aggregate allowDiskUse option (#913) Synced with mongodb/specifications@53b7f16fef2a340c76776ec5efc89d5471a91cd8 --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 84 +++ .../crud/aggregate-allowdiskuse.json | 155 ++++++ .../UnifiedSpecTests/crud/aggregate-let.json | 103 ---- tests/UnifiedSpecTests/crud/aggregate.json | 401 ++++++++++++++ .../crud/bulkWrite-comment.json | 518 ++++++++++++++++++ .../crud/bulkWrite-deleteMany-let.json | 200 +++++++ .../crud/bulkWrite-deleteOne-let.json | 200 +++++++ .../crud/bulkWrite-replaceOne-let.json | 226 ++++++++ .../crud/bulkWrite-updateMany-let.json | 243 ++++++++ .../crud/bulkWrite-updateOne-let.json | 247 +++++++++ .../crud/deleteMany-comment.json | 244 +++++++++ .../UnifiedSpecTests/crud/deleteMany-let.json | 201 +++++++ .../crud/deleteOne-comment.json | 242 ++++++++ .../UnifiedSpecTests/crud/deleteOne-let.json | 191 +++++++ .../crud/find-allowdiskuse.json | 4 +- tests/UnifiedSpecTests/crud/find-comment.json | 403 ++++++++++++++ tests/UnifiedSpecTests/crud/find-let.json | 148 +++++ .../crud/findOneAndDelete-comment.json | 211 +++++++ .../crud/findOneAndDelete-let.json | 180 ++++++ .../crud/findOneAndReplace-comment.json | 234 ++++++++ .../crud/findOneAndReplace-let.json | 197 +++++++ .../crud/findOneAndUpdate-comment.json | 228 ++++++++ .../crud/findOneAndUpdate-let.json | 217 ++++++++ .../crud/insertMany-comment.json | 225 ++++++++ .../crud/insertOne-comment.json | 219 ++++++++ .../crud/replaceOne-comment.json | 247 +++++++++ .../UnifiedSpecTests/crud/replaceOne-let.json | 219 ++++++++ .../crud/updateMany-comment.json | 253 +++++++++ .../UnifiedSpecTests/crud/updateMany-let.json | 249 +++++++++ .../crud/updateOne-comment.json | 259 +++++++++ .../UnifiedSpecTests/crud/updateOne-let.json | 227 ++++++++ 31 files changed, 6870 insertions(+), 105 deletions(-) create mode 100644 tests/UnifiedSpecTests/crud/aggregate-allowdiskuse.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-comment.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-let.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-let.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-let.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-updateMany-let.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-updateOne-let.json create mode 100644 tests/UnifiedSpecTests/crud/deleteMany-comment.json create mode 100644 tests/UnifiedSpecTests/crud/deleteMany-let.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-comment.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-let.json create mode 100644 tests/UnifiedSpecTests/crud/find-comment.json create mode 100644 tests/UnifiedSpecTests/crud/find-let.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndDelete-comment.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndDelete-let.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-comment.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndReplace-let.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-comment.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-let.json create mode 100644 tests/UnifiedSpecTests/crud/insertMany-comment.json create mode 100644 tests/UnifiedSpecTests/crud/insertOne-comment.json create mode 100644 tests/UnifiedSpecTests/crud/replaceOne-comment.json create mode 100644 tests/UnifiedSpecTests/crud/replaceOne-let.json create mode 100644 tests/UnifiedSpecTests/crud/updateMany-comment.json create mode 100644 tests/UnifiedSpecTests/crud/updateMany-let.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-comment.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-let.json diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 0ae0f36c9..f7275bf8b 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -61,6 +61,90 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType can be set to command and cmap' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType defaults to command if unset' => 'PHPC does not implement CMAP', + // CRUD "comment" option is not yet implemented + 'crud/bulkWrite-comment: BulkWrite with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/bulkWrite-comment: BulkWrite with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/bulkWrite-comment: BulkWrite with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/deleteMany-comment: deleteMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/deleteMany-comment: deleteMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/deleteMany-comment: deleteMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/deleteOne-comment: deleteOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/deleteOne-comment: deleteOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/deleteOne-comment: deleteOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/find-comment: find with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/find-comment: find with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/find-comment: find with document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/find-comment: find with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndDelete-comment: findOneAndDelete with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndDelete-comment: findOneAndDelete with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndDelete-comment: findOneAndDelete with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndReplace-comment: findOneAndReplace with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndReplace-comment: findOneAndReplace with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndReplace-comment: findOneAndReplace with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndUpdate-comment: findOneAndUpdate with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndUpdate-comment: findOneAndUpdate with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/findOneAndUpdate-comment: findOneAndUpdate with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/insertMany-comment: insertMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/insertMany-comment: insertMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/insertMany-comment: insertMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/insertOne-comment: insertOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/insertOne-comment: insertOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/insertOne-comment: insertOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/replaceOne-comment: ReplaceOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/replaceOne-comment: ReplaceOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/replaceOne-comment: ReplaceOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/updateMany-comment: UpdateMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/updateMany-comment: UpdateMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/updateMany-comment: UpdateMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/updateOne-comment: UpdateOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/updateOne-comment: UpdateOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/updateOne-comment: UpdateOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + // CRUD "let" option is not yet implemented + 'crud/BulkWrite deleteMany-let: BulkWrite deleteMany-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite deleteMany-let: BulkWrite deleteMany with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite deleteMany-let: BulkWrite deleteMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite deleteOne-let: BulkWrite deleteOne-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite deleteOne-let: BulkWrite deleteOne with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite deleteOne-let: BulkWrite deleteOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite replaceOne-let: BulkWrite replaceOne-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite replaceOne-let: BulkWrite replaceOne with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite replaceOne-let: BulkWrite replaceOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite updateMany-let: BulkWrite updateMany-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite updateMany-let: BulkWrite updateMany with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite updateMany-let: BulkWrite updateMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite updateOne-let: BulkWrite updateOne-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite updateOne-let: BulkWrite updateOne with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/BulkWrite updateOne-let: BulkWrite updateOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/deleteMany-let: deleteMany-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/deleteMany-let: deleteMany with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/deleteMany-let: deleteMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/deleteOne-let: deleteOne-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/deleteOne-let: deleteOne with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/deleteOne-let: deleteOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/find-let: find-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/find-let: Find with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/find-let: Find with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndDelete-let: findOneAndDelete-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndDelete-let: findOneAndDelete with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndDelete-let: findOneAndDelete with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndReplace-let: findOneAndReplace-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndReplace-let: findOneAndReplace with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndReplace-let: findOneAndReplace with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndUpdate-let: findOneAndUpdate-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndUpdate-let: findOneAndUpdate with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/findOneAndUpdate-let: findOneAndUpdate with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/replaceOne-let: replaceOne-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/replaceOne-let: ReplaceOne with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/replaceOne-let: ReplaceOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/updateMany-let: updateMany-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/updateMany-let: updateMany with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/updateMany-let: updateMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', + 'crud/updateOne-let: updateOne-let' => 'Not yet implemented (PHPLIB-748)', + 'crud/updateOne-let: UpdateOne with let option' => 'Not yet implemented (PHPLIB-748)', + 'crud/updateOne-let: UpdateOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/crud/aggregate-allowdiskuse.json b/tests/UnifiedSpecTests/crud/aggregate-allowdiskuse.json new file mode 100644 index 000000000..2e54175b8 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate-allowdiskuse.json @@ -0,0 +1,155 @@ +{ + "description": "aggregate-allowdiskuse", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "Aggregate does not send allowDiskUse when value is not specified", + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": {} + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": {} + } + ], + "allowDiskUse": { + "$$exists": false + } + }, + "commandName": "aggregate", + "databaseName": "crud-tests" + } + } + ] + } + ] + }, + { + "description": "Aggregate sends allowDiskUse false when false is specified", + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": {} + } + ], + "allowDiskUse": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": {} + } + ], + "allowDiskUse": false + }, + "commandName": "aggregate", + "databaseName": "crud-tests" + } + } + ] + } + ] + }, + { + "description": "Aggregate sends allowDiskUse true when true is specified", + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": {} + } + ], + "allowDiskUse": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": {} + } + ], + "allowDiskUse": true + }, + "commandName": "aggregate", + "databaseName": "crud-tests" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/aggregate-let.json b/tests/UnifiedSpecTests/crud/aggregate-let.json index d3b76bd65..039900920 100644 --- a/tests/UnifiedSpecTests/crud/aggregate-let.json +++ b/tests/UnifiedSpecTests/crud/aggregate-let.json @@ -56,109 +56,6 @@ "minServerVersion": "5.0" } ], - "operations": [ - { - "name": "aggregate", - "object": "collection0", - "arguments": { - "pipeline": [ - { - "$match": { - "$expr": { - "$eq": [ - "$_id", - "$$id" - ] - } - } - }, - { - "$project": { - "_id": 0, - "x": "$$x", - "y": "$$y", - "rand": "$$rand" - } - } - ], - "let": { - "id": 1, - "x": "foo", - "y": { - "$literal": "bar" - }, - "rand": { - "$rand": {} - } - } - }, - "expectResult": [ - { - "x": "foo", - "y": "bar", - "rand": { - "$$type": "double" - } - } - ] - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$match": { - "$expr": { - "$eq": [ - "$_id", - "$$id" - ] - } - } - }, - { - "$project": { - "_id": 0, - "x": "$$x", - "y": "$$y", - "rand": "$$rand" - } - } - ], - "let": { - "id": 1, - "x": "foo", - "y": { - "$literal": "bar" - }, - "rand": { - "$rand": {} - } - } - } - } - } - ] - } - ] - }, - { - "description": "Aggregate with let option and dollar-prefixed $literal value", - "runOnRequirements": [ - { - "minServerVersion": "5.0", - "topologies": [ - "single", - "replicaset" - ] - } - ], "operations": [ { "name": "aggregate", diff --git a/tests/UnifiedSpecTests/crud/aggregate.json b/tests/UnifiedSpecTests/crud/aggregate.json index dcdad761e..0cbfb4e6e 100644 --- a/tests/UnifiedSpecTests/crud/aggregate.json +++ b/tests/UnifiedSpecTests/crud/aggregate.json @@ -161,6 +161,407 @@ ] } ] + }, + { + "description": "aggregate with a string comment", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": "comment" + }, + "object": "collection0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "aggregate with a document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + }, + "object": "collection0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + } + } + } + ] + } + ] + }, + { + "description": "aggregate with a document comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "comment": { + "content": "test" + } + }, + "commandName": "aggregate", + "databaseName": "aggregate-tests" + } + } + ] + } + ] + }, + { + "description": "aggregate with comment sets comment on getMore", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "batchSize": 2, + "comment": { + "content": "test" + } + }, + "object": "collection0", + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "cursor": { + "batchSize": 2 + }, + "comment": { + "content": "test" + } + }, + "commandName": "aggregate", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "content": "test" + } + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "content": "test" + } + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + } + ] + } + ] + }, + { + "description": "aggregate with comment does not set comment on getMore - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.3.99" + } + ], + "operations": [ + { + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "batchSize": 2, + "comment": "comment" + }, + "object": "collection0", + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ], + "cursor": { + "batchSize": 2 + }, + "comment": "comment" + }, + "commandName": "aggregate", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + }, + "commandName": "getMore", + "databaseName": "aggregate-tests" + } + } + ] + } + ] } ] } diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-comment.json b/tests/UnifiedSpecTests/crud/bulkWrite-comment.json new file mode 100644 index 000000000..de044fca9 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-comment.json @@ -0,0 +1,518 @@ +{ + "description": "bulkWrite-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-v2" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "BulkWrite_comment" + } + } + ], + "initialData": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 5, + "x": "inserted" + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": "replaced" + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "updated" + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 3 + } + } + } + ], + "comment": "comment" + }, + "expectResult": { + "deletedCount": 1, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 5 + } + }, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "BulkWrite_comment", + "documents": [ + { + "_id": 5, + "x": "inserted" + } + ], + "ordered": true, + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "BulkWrite_comment", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "x": "replaced" + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": 2 + }, + "u": { + "$set": { + "x": "updated" + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true, + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_comment", + "deletes": [ + { + "q": { + "_id": 3 + }, + "limit": 1 + } + ], + "ordered": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": "replaced" + }, + { + "_id": 2, + "x": "updated" + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": "inserted" + } + ] + } + ] + }, + { + "description": "BulkWrite with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 5, + "x": "inserted" + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": "replaced" + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "updated" + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 3 + } + } + } + ], + "comment": { + "key": "value" + } + }, + "expectResult": { + "deletedCount": 1, + "insertedCount": 1, + "insertedIds": { + "$$unsetOrMatches": { + "0": 5 + } + }, + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0, + "upsertedIds": {} + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "BulkWrite_comment", + "documents": [ + { + "_id": 5, + "x": "inserted" + } + ], + "ordered": true, + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "update": "BulkWrite_comment", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "_id": 1, + "x": "replaced" + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": 2 + }, + "u": { + "$set": { + "x": "updated" + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true, + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "delete": "BulkWrite_comment", + "deletes": [ + { + "q": { + "_id": 3 + }, + "limit": 1 + } + ], + "ordered": true, + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": "replaced" + }, + { + "_id": 2, + "x": "updated" + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": "inserted" + } + ] + } + ] + }, + { + "description": "BulkWrite with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 5, + "x": "inserted" + } + } + }, + { + "replaceOne": { + "filter": { + "_id": 1 + }, + "replacement": { + "_id": 1, + "x": "replaced" + } + } + }, + { + "updateOne": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "updated" + } + } + } + }, + { + "deleteOne": { + "filter": { + "_id": 3 + } + } + } + ], + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "BulkWrite_comment", + "documents": [ + { + "_id": 5, + "x": "inserted" + } + ], + "ordered": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "BulkWrite_comment", + "databaseName": "crud-v2", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-let.json b/tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-let.json new file mode 100644 index 000000000..45c20ea49 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-deleteMany-let.json @@ -0,0 +1,200 @@ +{ + "description": "BulkWrite deleteMany-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite deleteMany with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteMany": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + } + } + ], + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "limit": 0 + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "BulkWrite deleteMany with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + } + } + ], + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'delete.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "limit": 1 + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-let.json b/tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-let.json new file mode 100644 index 000000000..f3268163c --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-deleteOne-let.json @@ -0,0 +1,200 @@ +{ + "description": "BulkWrite deleteOne-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite deleteOne with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + } + } + ], + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "limit": 1 + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "BulkWrite deleteOne with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.9" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "deleteOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + } + } + } + ], + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'delete.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "limit": 1 + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-let.json b/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-let.json new file mode 100644 index 000000000..70f63837a --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-replaceOne-let.json @@ -0,0 +1,226 @@ +{ + "description": "BulkWrite replaceOne-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite replaceOne with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "replacement": { + "x": 3 + } + } + } + ], + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": { + "x": 3 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 3 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "BulkWrite replaceOne with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.9" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "replaceOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "replacement": { + "x": 3 + } + } + } + ], + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'update.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": { + "x": 3 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-let.json b/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-let.json new file mode 100644 index 000000000..fbeba1a60 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-updateMany-let.json @@ -0,0 +1,243 @@ +{ + "description": "BulkWrite updateMany-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 20 + }, + { + "_id": 2, + "x": 21 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite updateMany with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": 21 + } + } + ] + } + } + ], + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": [ + { + "$set": { + "x": 21 + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 21 + }, + { + "_id": 2, + "x": 21 + } + ] + } + ] + }, + { + "description": "BulkWrite updateMany with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.9" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateMany": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": 21 + } + } + ] + } + } + ], + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'update.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": [ + { + "$set": { + "x": 21 + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 20 + }, + { + "_id": 2, + "x": 21 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-let.json b/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-let.json new file mode 100644 index 000000000..96783c782 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-updateOne-let.json @@ -0,0 +1,247 @@ +{ + "description": "BulkWrite updateOne-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 20 + }, + { + "_id": 2, + "x": 21 + } + ] + } + ], + "tests": [ + { + "description": "BulkWrite updateOne with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": 22 + } + } + ] + } + } + ], + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": [ + { + "$set": { + "x": 22 + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + }, + { + "_id": 2, + "x": 21 + } + ] + } + ] + }, + { + "description": "BulkWrite updateOne with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.9" + } + ], + "operations": [ + { + "object": "collection0", + "name": "bulkWrite", + "arguments": { + "requests": [ + { + "updateOne": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": 22 + } + } + ] + } + } + ], + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'update.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": [ + { + "$set": { + "x": 22 + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 20 + }, + { + "_id": 2, + "x": 21 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-comment.json b/tests/UnifiedSpecTests/crud/deleteMany-comment.json new file mode 100644 index 000000000..ea6a8524d --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteMany-comment.json @@ -0,0 +1,244 @@ +{ + "description": "deleteMany-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name2" + }, + { + "_id": 3, + "name": "name3" + } + ] + } + ], + "tests": [ + { + "description": "deleteMany with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "comment": "comment" + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "deleteMany with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "deleteMany with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name2" + }, + { + "_id": 3, + "name": "name3" + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-let.json b/tests/UnifiedSpecTests/crud/deleteMany-let.json new file mode 100644 index 000000000..71bf26a01 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteMany-let.json @@ -0,0 +1,201 @@ +{ + "description": "deleteMany-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ], + "tests": [ + { + "description": "deleteMany with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$name", + "$$name" + ] + } + }, + "let": { + "name": "name" + } + }, + "expectResult": { + "deletedCount": 2 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$name", + "$$name" + ] + } + }, + "limit": 0 + } + ], + "let": { + "name": "name" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ] + }, + { + "description": "deleteMany with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "deleteMany", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$name", + "$$name" + ] + } + }, + "let": { + "name": "name" + } + }, + "expectError": { + "errorContains": "'delete.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$name", + "$$name" + ] + } + }, + "limit": 0 + } + ], + "let": { + "name": "name" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-comment.json b/tests/UnifiedSpecTests/crud/deleteOne-comment.json new file mode 100644 index 000000000..37f356ec6 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-comment.json @@ -0,0 +1,242 @@ +{ + "description": "deleteOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ], + "tests": [ + { + "description": "deleteOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + }, + { + "description": "deleteOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + }, + { + "description": "deleteOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-let.json b/tests/UnifiedSpecTests/crud/deleteOne-let.json new file mode 100644 index 000000000..971868223 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-let.json @@ -0,0 +1,191 @@ +{ + "description": "deleteOne-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "deleteOne with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "let": { + "id": 1 + } + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "limit": 1 + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "deleteOne with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'delete.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll0", + "deletes": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "limit": 1 + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/find-allowdiskuse.json b/tests/UnifiedSpecTests/crud/find-allowdiskuse.json index 789bb7fbf..eb238ab93 100644 --- a/tests/UnifiedSpecTests/crud/find-allowdiskuse.json +++ b/tests/UnifiedSpecTests/crud/find-allowdiskuse.json @@ -32,7 +32,7 @@ ], "tests": [ { - "description": "Find does not send allowDiskuse when value is not specified", + "description": "Find does not send allowDiskUse when value is not specified", "operations": [ { "object": "collection0", @@ -61,7 +61,7 @@ ] }, { - "description": "Find sends allowDiskuse false when false is specified", + "description": "Find sends allowDiskUse false when false is specified", "operations": [ { "object": "collection0", diff --git a/tests/UnifiedSpecTests/crud/find-comment.json b/tests/UnifiedSpecTests/crud/find-comment.json new file mode 100644 index 000000000..600a3723f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/find-comment.json @@ -0,0 +1,403 @@ +{ + "description": "find-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "tests": [ + { + "description": "find with string comment", + "runOnRequirements": [ + { + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectResult": [ + { + "_id": 1 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "find with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectResult": [ + { + "_id": 1 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "find with document comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99", + "minServerVersion": "3.6" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "find with comment sets comment on getMore", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2, + "comment": { + "key": "value" + } + }, + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2, + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "find with comment does not set comment on getMore - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.3.99" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2, + "comment": "comment" + }, + "expectResult": [ + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + }, + { + "_id": 6, + "x": 66 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": { + "$gt": 1 + } + }, + "batchSize": 2, + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "coll0", + "batchSize": 2, + "comment": { + "$$exists": false + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/find-let.json b/tests/UnifiedSpecTests/crud/find-let.json new file mode 100644 index 000000000..4e9c9c99f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/find-let.json @@ -0,0 +1,148 @@ +{ + "description": "find-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "Find with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "let": { + "id": 1 + } + }, + "expectResult": [ + { + "_id": 1 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "let": { + "id": 1 + } + } + } + } + ] + } + ] + }, + { + "description": "Find with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "let": { + "x": 1 + } + }, + "expectError": { + "errorContains": "Unrecognized field 'let'", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": { + "_id": 1 + }, + "let": { + "x": 1 + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-comment.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-comment.json new file mode 100644 index 000000000..6853b9cc2 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-comment.json @@ -0,0 +1,211 @@ +{ + "description": "findOneAndDelete-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndDelete with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "remove": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndDelete with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "remove": true, + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndDelete with comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "remove": true, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndDelete-let.json b/tests/UnifiedSpecTests/crud/findOneAndDelete-let.json new file mode 100644 index 000000000..ba8e681c0 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndDelete-let.json @@ -0,0 +1,180 @@ +{ + "description": "findOneAndDelete-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndDelete with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "let": { + "id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "remove": true, + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndDelete with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "findOneAndDelete", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "field 'let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "remove": true, + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-comment.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-comment.json new file mode 100644 index 000000000..f817bb693 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-comment.json @@ -0,0 +1,234 @@ +{ + "description": "findOneAndReplace-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndReplace with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 5 + }, + "comment": "comment" + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "x": 5 + }, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 5 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndReplace with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 5 + }, + "comment": { + "key": "value" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "x": 5 + }, + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 5 + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndReplace with comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 5 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": { + "x": 5 + }, + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndReplace-let.json b/tests/UnifiedSpecTests/crud/findOneAndReplace-let.json new file mode 100644 index 000000000..5e5de44b3 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndReplace-let.json @@ -0,0 +1,197 @@ +{ + "description": "findOneAndReplace-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndReplace with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "replacement": { + "x": "x" + }, + "let": { + "id": 1 + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": { + "x": "x" + }, + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": "x" + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndReplace with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "findOneAndReplace", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "replacement": { + "x": "x" + }, + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "field 'let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": { + "x": "x" + }, + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-comment.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-comment.json new file mode 100644 index 000000000..6dec5b39e --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-comment.json @@ -0,0 +1,228 @@ +{ + "description": "findOneAndUpdate-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndUpdate with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "findOneAndUpdate with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": { + "key": "value" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ] + }, + { + "description": "findOneAndUpdate with comment - pre 4.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": 5 + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-let.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-let.json new file mode 100644 index 000000000..74d7d0e58 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-let.json @@ -0,0 +1,217 @@ +{ + "description": "findOneAndUpdate-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "findOneAndUpdate with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "id": 1, + "x": "foo" + } + }, + "expectResult": { + "_id": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "id": 1, + "x": "foo" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": "foo" + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "findOneAndUpdate with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "id": 1, + "x": "foo" + } + }, + "expectError": { + "errorContains": "field 'let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "findAndModify": "coll0", + "query": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "id": 1, + "x": "foo" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/insertMany-comment.json b/tests/UnifiedSpecTests/crud/insertMany-comment.json new file mode 100644 index 000000000..7e835e801 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/insertMany-comment.json @@ -0,0 +1,225 @@ +{ + "description": "insertMany-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "insertMany with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertMany with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertMany with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "insertMany", + "object": "collection0", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/insertOne-comment.json b/tests/UnifiedSpecTests/crud/insertOne-comment.json new file mode 100644 index 000000000..a9f735ab6 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/insertOne-comment.json @@ -0,0 +1,219 @@ +{ + "description": "insertOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "insertOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2, + "x": 22 + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2, + "x": 22 + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + }, + { + "description": "insertOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2, + "x": 22 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-comment.json b/tests/UnifiedSpecTests/crud/replaceOne-comment.json new file mode 100644 index 000000000..bcd8aca22 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/replaceOne-comment.json @@ -0,0 +1,247 @@ +{ + "description": "replaceOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "ReplaceOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 22 + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 22 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "ReplaceOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 22 + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 22 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "ReplaceOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 22 + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 22 + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/replaceOne-let.json b/tests/UnifiedSpecTests/crud/replaceOne-let.json new file mode 100644 index 000000000..e7a7ee65a --- /dev/null +++ b/tests/UnifiedSpecTests/crud/replaceOne-let.json @@ -0,0 +1,219 @@ +{ + "description": "replaceOne-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "ReplaceOne with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "replacement": { + "x": "foo" + }, + "let": { + "id": 1 + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": { + "x": "foo" + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": "foo" + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "ReplaceOne with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "replaceOne", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "replacement": { + "x": "foo" + }, + "let": { + "id": 1 + } + }, + "expectError": { + "errorContains": "'update.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": { + "x": "foo" + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1 + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateMany-comment.json b/tests/UnifiedSpecTests/crud/updateMany-comment.json new file mode 100644 index 000000000..641108452 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-comment.json @@ -0,0 +1,253 @@ +{ + "description": "updateMany-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "UpdateMany with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateMany with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateMany with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateMany-let.json b/tests/UnifiedSpecTests/crud/updateMany-let.json new file mode 100644 index 000000000..cff3bd4c7 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateMany-let.json @@ -0,0 +1,249 @@ +{ + "description": "updateMany-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ], + "tests": [ + { + "description": "updateMany with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$name", + "$$name" + ] + } + }, + "update": [ + { + "$set": { + "x": "$$x", + "y": "$$y" + } + } + ], + "let": { + "name": "name", + "x": "foo", + "y": { + "$literal": "bar" + } + } + }, + "expectResult": { + "matchedCount": 2, + "modifiedCount": 2, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$name", + "$$name" + ] + } + }, + "u": [ + { + "$set": { + "x": "$$x", + "y": "$$y" + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "name": "name", + "x": "foo", + "y": { + "$literal": "bar" + } + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name", + "x": "foo", + "y": "bar" + }, + { + "_id": 3, + "name": "name", + "x": "foo", + "y": "bar" + } + ] + } + ] + }, + { + "description": "updateMany with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "updateMany", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "x": "foo" + } + }, + "expectError": { + "errorContains": "'update.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "x": "$$x" + } + } + ], + "multi": true, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "x": "foo" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2, + "name": "name" + }, + { + "_id": 3, + "name": "name" + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-comment.json b/tests/UnifiedSpecTests/crud/updateOne-comment.json new file mode 100644 index 000000000..c18f59cfb --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-comment.json @@ -0,0 +1,259 @@ +{ + "description": "updateOne-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateOne with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": { + "key": "value" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": { + "key": "value" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 22 + } + ] + } + ] + }, + { + "description": "UpdateOne with comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 22 + } + }, + "comment": "comment" + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 22 + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "comment": "comment" + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-let.json b/tests/UnifiedSpecTests/crud/updateOne-let.json new file mode 100644 index 000000000..e43b97935 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-let.json @@ -0,0 +1,227 @@ +{ + "description": "updateOne-let", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ], + "tests": [ + { + "description": "UpdateOne with let option", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "id": 1, + "x": "foo" + } + }, + "expectResult": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "$expr": { + "$eq": [ + "$_id", + "$$id" + ] + } + }, + "u": [ + { + "$set": { + "x": "$$x" + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "id": 1, + "x": "foo" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": "foo" + }, + { + "_id": 2 + } + ] + } + ] + }, + { + "description": "UpdateOne with let option unsupported (server-side error)", + "runOnRequirements": [ + { + "minServerVersion": "4.2.0", + "maxServerVersion": "4.4.99" + } + ], + "operations": [ + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": [ + { + "$set": { + "x": "$$x" + } + } + ], + "let": { + "x": "foo" + } + }, + "expectError": { + "errorContains": "'update.let' is an unknown field", + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "coll0", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": [ + { + "$set": { + "x": "$$x" + } + } + ], + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "let": { + "x": "foo" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll0", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + } + ] + } + ] + } + ] +} From 20e8f917f51d99b8a70137cd1d272c1fb8f42ba9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 14 Apr 2022 09:59:27 -0400 Subject: [PATCH 129/321] PHPLIB-652: Convert change streams to unified test format (#908) * PHPLIB-652: Update unified test runner for change stream tests This bumps the supported schema version to 1.7, but omits support for 1.6 (see: PHPLIB-718). Also includes spec tests for PHPLIB-828 and PHPLIB-829 and introduces support for Collection::rename() operation. Change stream tests synced with mongodb/specifications@bb7a784f8411d313dfbfec107d245490102f2649. Unified spec tests synced with mongodb/specifications@ff0c705f9cc95a5a9c8c595dbf9384cb41dfcdd2. * Remove legacy change stream spec test runner --- tests/SpecTests/ChangeStreamsSpecTest.php | 301 --- tests/SpecTests/CommandExpectations.php | 14 - tests/SpecTests/ErrorExpectation.php | 21 - tests/SpecTests/Operation.php | 40 - tests/SpecTests/ResultExpectation.php | 13 - .../change-streams/change-streams-errors.json | 153 -- .../change-streams-resume-allowlist.json | 1750 ------------ .../change-streams-resume-errorLabels.json | 1652 ------------ .../change-streams/change-streams.json | 795 ------ tests/UnifiedSpecTests/Context.php | 5 +- tests/UnifiedSpecTests/EventObserver.php | 13 +- tests/UnifiedSpecTests/Operation.php | 6 + tests/UnifiedSpecTests/UnifiedSpecTest.php | 3 + tests/UnifiedSpecTests/UnifiedTestRunner.php | 4 +- tests/UnifiedSpecTests/Util.php | 1 + .../change-streams/change-streams-errors.json | 234 ++ .../change-streams-resume-allowlist.json | 2347 +++++++++++++++++ .../change-streams-resume-errorLabels.json | 2124 +++++++++++++++ .../change-streams/change-streams.json | 1676 +++++++++++- ...ctedEventsForClient-ignoreExtraEvents.json | 151 ++ 20 files changed, 6553 insertions(+), 4750 deletions(-) delete mode 100644 tests/SpecTests/ChangeStreamsSpecTest.php delete mode 100644 tests/SpecTests/change-streams/change-streams-errors.json delete mode 100644 tests/SpecTests/change-streams/change-streams-resume-allowlist.json delete mode 100644 tests/SpecTests/change-streams/change-streams-resume-errorLabels.json delete mode 100644 tests/SpecTests/change-streams/change-streams.json create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-errors.json create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json create mode 100644 tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-ignoreExtraEvents.json diff --git a/tests/SpecTests/ChangeStreamsSpecTest.php b/tests/SpecTests/ChangeStreamsSpecTest.php deleted file mode 100644 index c0ef72003..000000000 --- a/tests/SpecTests/ChangeStreamsSpecTest.php +++ /dev/null @@ -1,301 +0,0 @@ -getMore) && $expected->getMore === 42) { - static::assertObjectHasAttribute('getMore', $actual); - static::assertThat($actual->getMore, static::logicalOr( - static::isInstanceOf(Int64::class), - static::isType('integer') - )); - unset($expected->getMore); - } - - static::assertDocumentsMatch($expected, $actual); - } - - /** - * Assert that the expected and actual documents match. - * - * @param array $expectedDocuments Expected documents - * @param array $actualDocuments Actual documents - */ - public static function assertResult(array $expectedDocuments, array $actualDocuments): void - { - static::assertCount(count($expectedDocuments), $actualDocuments); - - $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); - $mi->attachIterator(new ArrayIterator($expectedDocuments)); - $mi->attachIterator(new ArrayIterator($actualDocuments)); - - foreach ($mi as $documents) { - [$expectedDocument, $actualDocument] = $documents; - - $constraint = new DocumentsMatchConstraint($expectedDocument, true, true, ['42']); - - static::assertThat($actualDocument, $constraint); - } - } - - /** - * Execute an individual test case from the specification. - * - * @dataProvider provideTests - * @param stdClass $test Individual "tests[]" document - * @param string $databaseName Name of database under test - * @param string $collectionName Name of collection under test - * @param string $database2Name Name of alternate database under test - * @param string $collection2Name Name of alternate collection under test - */ - public function testChangeStreams(stdClass $test, ?string $databaseName = null, ?string $collectionName = null, ?string $database2Name = null, ?string $collection2Name = null): void - { - if (isset(self::$incompleteTests[$this->dataDescription()])) { - $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); - } - - if ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets()) { - $this->markTestSkipped('$changeStream is only supported with replicasets'); - } - - $this->checkServerRequirements($this->createRunOn($test)); - - if (! isset($databaseName, $collectionName)) { - $this->fail('Required database and collection names are unset'); - } - - $context = Context::fromChangeStreams($test, $databaseName, $collectionName); - $this->setContext($context); - - $this->dropDatabasesAndCreateCollection($databaseName, $collectionName); - - if (isset($database2Name, $collection2Name)) { - $this->dropDatabasesAndCreateCollection($database2Name, $collection2Name); - } - - if (isset($test->failPoint)) { - $this->configureFailPoint($test->failPoint); - } - - if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromChangeStreams($test->expectations); - $commandExpectations->startMonitoring(); - } - - $errorExpectation = ErrorExpectation::fromChangeStreams($test->result); - $resultExpectation = ResultExpectation::fromChangeStreams($test->result, [$this, 'assertResult']); - - $result = null; - $exception = null; - - try { - $changeStream = $this->createChangeStream($test); - } catch (Exception $e) { - $exception = $e; - } - - if (isset($commandExpectations)) { - $commandExpectations->stopMonitoring(); - } - - foreach ($test->operations as $operation) { - Operation::fromChangeStreams($operation)->assert($this, $context); - } - - if (isset($commandExpectations)) { - $commandExpectations->startMonitoring(); - } - - /* If the change stream was successfully created (i.e. $exception is - * null), attempt to iterate up to the expected number of results. It's - * possible that some errors (e.g. projecting out _id) will only be - * thrown during iteration, so we must also try/catch here. */ - try { - if (isset($changeStream)) { - $limit = isset($test->result->success) ? count($test->result->success) : 0; - $result = $this->iterateChangeStream($changeStream, $limit); - } - } catch (Exception $e) { - $this->assertNull($exception); - $exception = $e; - } - - $errorExpectation->assert($this, $exception); - $resultExpectation->assert($this, $result); - - if (isset($commandExpectations)) { - $commandExpectations->stopMonitoring(); - $commandExpectations->assert($this, $context); - } - } - - public function provideTests() - { - $testArgs = []; - - foreach (glob(__DIR__ . '/change-streams/*.json') as $filename) { - $json = $this->decodeJson(file_get_contents($filename)); - $group = basename($filename, '.json'); - // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - $databaseName = $json->database_name ?? null; - $database2Name = $json->database2_name ?? null; - $collectionName = $json->collection_name ?? null; - $collection2Name = $json->collection2_name ?? null; - // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - - foreach ($json->tests as $test) { - $name = $group . ': ' . $test->description; - $testArgs[$name] = [$test, $databaseName, $collectionName, $database2Name, $collection2Name]; - } - } - - return $testArgs; - } - - /** - * Create a change stream. - * - * @param stdClass $test - * @return ChangeStream - * @throws LogicException if the target is unsupported - */ - private function createChangeStream(stdClass $test): ChangeStream - { - $context = $this->getContext(); - $pipeline = $test->changeStreamPipeline ?? []; - $options = isset($test->changeStreamOptions) ? (array) $test->changeStreamOptions : []; - - switch ($test->target) { - case 'client': - return $context->getClient()->watch($pipeline, $options); - - case 'database': - return $context->getDatabase()->watch($pipeline, $options); - - case 'collection': - return $context->getCollection()->watch($pipeline, $options); - - default: - throw new LogicException('Unsupported target: ' . $test->target); - } - } - - /** - * Convert the server requirements to a standard "runOn" array used by other - * specifications. - * - * @param stdClass $test - * @return array - */ - private function createRunOn(stdClass $test): array - { - $req = new stdClass(); - - /* Append ".99" as patch version, since command monitoring tests expect - * the minor version to be an inclusive upper bound. */ - if (isset($test->maxServerVersion)) { - $req->maxServerVersion = $test->maxServerVersion; - } - - if (isset($test->minServerVersion)) { - $req->minServerVersion = $test->minServerVersion; - } - - if (isset($test->topology)) { - $req->topology = $test->topology; - } - - return [$req]; - } - - /** - * Drop the database and create the collection. - * - * @param string $databaseName - * @param string $collectionName - */ - private function dropDatabasesAndCreateCollection(string $databaseName, string $collectionName): void - { - $context = $this->getContext(); - - $database = $context->getClient()->selectDatabase($databaseName); - $database->drop($context->defaultWriteOptions); - $database->createCollection($collectionName, $context->defaultWriteOptions); - } - - /** - * Iterate a change stream. - * - * @param ChangeStream $changeStream - * @param integer $limit - * @return BSONDocument[] - */ - private function iterateChangeStream(ChangeStream $changeStream, int $limit = 0): array - { - if ($limit < 0) { - throw new LogicException('$limit is negative'); - } - - /* Limit iterations to guard against an infinite loop should a test fail - * to return as many results as are expected. Require at least one - * iteration to allow next() a chance to throw for error tests. */ - $maxIterations = $limit + 1; - - /* On sharded clusters, allow for empty getMore calls due to sharding - * architecture */ - if ($this->isShardedCluster()) { - $maxIterations *= 5; - } - - $events = []; - - for ($i = 0, $changeStream->rewind(); $i < $maxIterations; $i++, $changeStream->next()) { - if (! $changeStream->valid()) { - continue; - } - - $event = $changeStream->current(); - $this->assertInstanceOf(BSONDocument::class, $event); - $events[] = $event; - - if (count($events) >= $limit) { - break; - } - } - - return $events; - } -} diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index 428ead145..b33979851 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -70,20 +70,6 @@ private function __construct(array $events) } } - public static function fromChangeStreams(array $expectedEvents) - { - $o = new self($expectedEvents); - - $o->ignoreCommandFailed = true; - $o->ignoreCommandSucceeded = true; - /* Change Streams spec tests do not include getMore commands in the - * list of expected events, so ignore any observed events beyond the - * number that are expected. */ - $o->ignoreExtraEvents = true; - - return $o; - } - public static function fromClientSideEncryption(array $expectedEvents) { $o = new self($expectedEvents); diff --git a/tests/SpecTests/ErrorExpectation.php b/tests/SpecTests/ErrorExpectation.php index 9f40d003a..07164eba6 100644 --- a/tests/SpecTests/ErrorExpectation.php +++ b/tests/SpecTests/ErrorExpectation.php @@ -57,27 +57,6 @@ private function __construct() { } - public static function fromChangeStreams(stdClass $result) - { - $o = new self(); - - if (isset($result->error->code)) { - $o->code = $result->error->code; - $o->isExpected = true; - } - - if (isset($result->error->errorLabels)) { - if (! self::isArrayOfStrings($result->error->errorLabels)) { - throw InvalidArgumentException::invalidType('errorLabels', $result->error->errorLabels, 'string[]'); - } - - $o->includedLabels = $result->error->errorLabels; - $o->isExpected = true; - } - - return $o; - } - public static function fromClientSideEncryption(stdClass $operation) { return self::fromGenericOperation($operation); diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index 626cd313f..82f2fa65f 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -11,7 +11,6 @@ use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\Server; use MongoDB\Driver\Session; -use MongoDB\Driver\WriteConcern; use MongoDB\GridFS\Bucket; use MongoDB\Model\IndexInfo; use MongoDB\Operation\FindOneAndReplace; @@ -83,45 +82,6 @@ private function __construct(stdClass $operation) } } - public static function fromChangeStreams(stdClass $operation) - { - $o = new self($operation); - - /* Note: change streams only return majority-committed writes, so ensure - * each operation applies that write concern. This will avoid spurious - * test failures. */ - $writeConcern = new WriteConcern(WriteConcern::MAJORITY); - - // Expect all operations to succeed - $o->errorExpectation = ErrorExpectation::noError(); - - /* The Change Streams spec tests include a unique "rename" operation, - * which we should convert to a renameCollection command to be run - * against the admin database. */ - if ($operation->name === 'rename') { - $o->object = self::OBJECT_SELECT_DATABASE; - $o->databaseName = 'admin'; - $o->name = 'runCommand'; - $o->arguments = [ - 'command' => [ - 'renameCollection' => $operation->database . '.' . $operation->collection, - 'to' => $operation->database . '.' . $operation->arguments->to, - // Note: Database::command() does not inherit WC, so be explicit - 'writeConcern' => $writeConcern, - ], - ]; - - return $o; - } - - $o->databaseName = $operation->database; - $o->collectionName = $operation->collection; - $o->collectionOptions = ['writeConcern' => $writeConcern]; - $o->object = self::OBJECT_SELECT_COLLECTION; - - return $o; - } - public static function fromClientSideEncryption(stdClass $operation) { $o = new self($operation); diff --git a/tests/SpecTests/ResultExpectation.php b/tests/SpecTests/ResultExpectation.php index 96e5640b6..bb6f1c282 100644 --- a/tests/SpecTests/ResultExpectation.php +++ b/tests/SpecTests/ResultExpectation.php @@ -75,19 +75,6 @@ private function __construct(int $assertionType, $expectedValue) $this->expectedValue = $expectedValue; } - public static function fromChangeStreams(stdClass $result, callable $assertionCallable) - { - if (! property_exists($result, 'success')) { - return new self(self::ASSERT_NOTHING, null); - } - - $o = new self(self::ASSERT_CALLABLE, $result->success); - - $o->assertionCallable = $assertionCallable; - - return $o; - } - public static function fromClientSideEncryption(stdClass $operation, $defaultAssertionType) { if (property_exists($operation, 'result') && ! self::isErrorResult($operation->result)) { diff --git a/tests/SpecTests/change-streams/change-streams-errors.json b/tests/SpecTests/change-streams/change-streams-errors.json deleted file mode 100644 index 7b3fa8068..000000000 --- a/tests/SpecTests/change-streams/change-streams-errors.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "collection_name": "test", - "database_name": "change-stream-tests", - "collection2_name": "test2", - "database2_name": "change-stream-tests-2", - "tests": [ - { - "description": "The watch helper must not throw a custom exception when executed against a single server topology, but instead depend on a server error", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "single" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [], - "expectations": null, - "result": { - "error": { - "code": 40573 - } - } - }, - { - "description": "Change Stream should error when an invalid aggregation stage is passed in", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [ - { - "$unsupported": "foo" - } - ], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - }, - { - "$unsupported": "foo" - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "error": { - "code": 40324 - } - } - }, - { - "description": "Change Stream should error when _id is projected out", - "minServerVersion": "4.1.11", - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [ - { - "$project": { - "_id": 0 - } - } - ], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "result": { - "error": { - "code": 280 - } - } - }, - { - "description": "change stream errors on ElectionInProgress", - "minServerVersion": "4.2", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 216, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "result": { - "error": { - "code": 216 - } - } - } - ] -} diff --git a/tests/SpecTests/change-streams/change-streams-resume-allowlist.json b/tests/SpecTests/change-streams/change-streams-resume-allowlist.json deleted file mode 100644 index baffc8fba..000000000 --- a/tests/SpecTests/change-streams/change-streams-resume-allowlist.json +++ /dev/null @@ -1,1750 +0,0 @@ -{ - "collection_name": "test", - "database_name": "change-stream-tests", - "tests": [ - { - "description": "change stream resumes after a network error", - "minServerVersion": "4.2", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "closeConnection": true - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after HostUnreachable", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 6, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after HostNotFound", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 7, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NetworkTimeout", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 89, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after ShutdownInProgress", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 91, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after PrimarySteppedDown", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 189, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after ExceededTimeLimit", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 262, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after SocketException", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 9001, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NotWritablePrimary", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 10107, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after InterruptedAtShutdown", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 11600, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after InterruptedDueToReplStateChange", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 11602, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NotPrimaryNoSecondaryOk", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 13435, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NotPrimaryOrSecondary", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 13436, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after StaleShardVersion", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 63, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after StaleEpoch", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 150, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after RetryChangeStream", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 234, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after FailedToSatisfyReadPreference", - "minServerVersion": "4.2", - "maxServerVersion": "4.2.99", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 133, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after CursorNotFound", - "minServerVersion": "4.2", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 43, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - } - ] -} diff --git a/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json b/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json deleted file mode 100644 index 2bac61d3b..000000000 --- a/tests/SpecTests/change-streams/change-streams-resume-errorLabels.json +++ /dev/null @@ -1,1652 +0,0 @@ -{ - "collection_name": "test", - "database_name": "change-stream-tests", - "tests": [ - { - "description": "change stream resumes after HostUnreachable", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 6, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after HostNotFound", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 7, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NetworkTimeout", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 89, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after ShutdownInProgress", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 91, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after PrimarySteppedDown", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 189, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after ExceededTimeLimit", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 262, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after SocketException", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 9001, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NotWritablePrimary", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 10107, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after InterruptedAtShutdown", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 11600, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after InterruptedDueToReplStateChange", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 11602, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NotPrimaryNoSecondaryOk", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 13435, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after NotPrimaryOrSecondary", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 13436, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after StaleShardVersion", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 63, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after StaleEpoch", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 150, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after RetryChangeStream", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 234, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes after FailedToSatisfyReadPreference", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failGetMoreAfterCursorCheckout", - "mode": { - "times": 1 - }, - "data": { - "errorCode": 133, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream resumes if error contains ResumableChangeStreamError", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 50, - "closeConnection": false, - "errorLabels": [ - "ResumableChangeStreamError" - ] - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "getMore": 42, - "collection": "test" - }, - "command_name": "getMore", - "database_name": "change-stream-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "change stream does not resume if error does not contain ResumableChangeStreamError", - "minServerVersion": "4.3.1", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "getMore" - ], - "errorCode": 6, - "closeConnection": false - } - }, - "target": "collection", - "topology": [ - "replicaset", - "sharded", - "load-balanced" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "result": { - "error": { - "code": 6 - } - } - } - ] -} diff --git a/tests/SpecTests/change-streams/change-streams.json b/tests/SpecTests/change-streams/change-streams.json deleted file mode 100644 index 54b76af0a..000000000 --- a/tests/SpecTests/change-streams/change-streams.json +++ /dev/null @@ -1,795 +0,0 @@ -{ - "collection_name": "test", - "database_name": "change-stream-tests", - "collection2_name": "test2", - "database2_name": "change-stream-tests-2", - "tests": [ - { - "description": "$changeStream must be the first stage in a change stream pipeline sent to the server", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "The server returns change stream responses in the specified server response format", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - } - ], - "expectations": null, - "result": { - "success": [ - { - "_id": "42", - "documentKey": "42", - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - } - ] - } - }, - { - "description": "Executing a watch helper on a Collection results in notifications for changes to the specified collection", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test2", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - }, - { - "database": "change-stream-tests-2", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "y": 2 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "z": { - "$numberInt": "3" - } - } - } - ] - } - }, - { - "description": "Change Stream should allow valid aggregate pipeline stages", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [ - { - "$match": { - "fullDocument.z": 3 - } - } - ], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "y": 2 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - }, - { - "$match": { - "fullDocument.z": { - "$numberInt": "3" - } - } - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "z": { - "$numberInt": "3" - } - } - } - ] - } - }, - { - "description": "Executing a watch helper on a Database results in notifications for changes to all collections in the specified database.", - "minServerVersion": "3.8.0", - "target": "database", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test2", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - }, - { - "database": "change-stream-tests-2", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "y": 2 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": { - "$numberInt": "1" - }, - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test2" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - }, - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "z": { - "$numberInt": "3" - } - } - } - ] - } - }, - { - "description": "Executing a watch helper on a MongoClient results in notifications for changes to all collections in all databases in the cluster.", - "minServerVersion": "3.8.0", - "target": "client", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test2", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - }, - { - "database": "change-stream-tests-2", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "y": 2 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "z": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": { - "$numberInt": "1" - }, - "cursor": {}, - "pipeline": [ - { - "$changeStream": { - "allChangesForCluster": true - } - } - ] - }, - "command_name": "aggregate", - "database_name": "admin" - } - } - ], - "result": { - "success": [ - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test2" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - }, - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests-2", - "coll": "test" - }, - "fullDocument": { - "y": { - "$numberInt": "2" - } - } - }, - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "z": { - "$numberInt": "3" - } - } - } - ] - } - }, - { - "description": "Test insert, update, replace, and delete event types", - "minServerVersion": "3.6.0", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "updateOne", - "arguments": { - "filter": { - "x": 1 - }, - "update": { - "$set": { - "x": 2 - } - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "replaceOne", - "arguments": { - "filter": { - "x": 2 - }, - "replacement": { - "x": 3 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "deleteOne", - "arguments": { - "filter": { - "x": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - }, - { - "operationType": "update", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "updateDescription": { - "updatedFields": { - "x": { - "$numberInt": "2" - } - } - } - }, - { - "operationType": "replace", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "3" - } - } - }, - { - "operationType": "delete", - "ns": { - "db": "change-stream-tests", - "coll": "test" - } - } - ] - } - }, - { - "description": "Test rename and invalidate event types", - "minServerVersion": "4.0.1", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "rename", - "arguments": { - "to": "test2" - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "rename", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "to": { - "db": "change-stream-tests", - "coll": "test2" - } - }, - { - "operationType": "invalidate" - } - ] - } - }, - { - "description": "Test drop and invalidate event types", - "minServerVersion": "4.0.1", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": {}, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "drop" - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": {}, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "drop", - "ns": { - "db": "change-stream-tests", - "coll": "test" - } - }, - { - "operationType": "invalidate" - } - ] - } - }, - { - "description": "Test consecutive resume", - "minServerVersion": "4.1.7", - "target": "collection", - "topology": [ - "replicaset" - ], - "changeStreamPipeline": [], - "changeStreamOptions": { - "batchSize": 1 - }, - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 2 - }, - "data": { - "failCommands": [ - "getMore" - ], - "closeConnection": true - } - }, - "operations": [ - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 1 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 2 - } - } - }, - { - "database": "change-stream-tests", - "collection": "test", - "name": "insertOne", - "arguments": { - "document": { - "x": 3 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "test", - "cursor": { - "batchSize": 1 - }, - "pipeline": [ - { - "$changeStream": {} - } - ] - }, - "command_name": "aggregate", - "database_name": "change-stream-tests" - } - } - ], - "result": { - "success": [ - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "1" - } - } - }, - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "2" - } - } - }, - { - "operationType": "insert", - "ns": { - "db": "change-stream-tests", - "coll": "test" - }, - "fullDocument": { - "x": { - "$numberInt": "3" - } - } - } - ] - } - } - ] -} diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index c47219988..27214aae7 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -156,11 +156,12 @@ public function assertExpectedEventsForClients(array $expectedEventsForClients): foreach ($expectedEventsForClients as $expectedEventsForClient) { assertIsObject($expectedEventsForClient); - Util::assertHasOnlyKeys($expectedEventsForClient, ['client', 'events', 'eventType']); + Util::assertHasOnlyKeys($expectedEventsForClient, ['client', 'events', 'eventType', 'ignoreExtraEvents']); $client = $expectedEventsForClient->client ?? null; $eventType = $expectedEventsForClient->eventType ?? 'command'; $expectedEvents = $expectedEventsForClient->events ?? null; + $ignoreExtraEvents = $expectedEventsForClient->ignoreExtraEvents ?? false; assertIsString($client); assertArrayHasKey($client, $this->eventObserversByClient); @@ -169,7 +170,7 @@ public function assertExpectedEventsForClients(array $expectedEventsForClients): assertSame('command', $eventType); assertIsArray($expectedEvents); - $this->eventObserversByClient[$client]->assert($expectedEvents); + $this->eventObserversByClient[$client]->assert($expectedEvents, $ignoreExtraEvents); } } diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index 3404ac2a4..651d21b2d 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -22,6 +22,7 @@ use function MongoDB\Driver\Monitoring\removeSubscriber; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertCount; +use function PHPUnit\Framework\assertGreaterThanOrEqual; use function PHPUnit\Framework\assertInstanceOf; use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsObject; @@ -204,9 +205,13 @@ public function getLsidsOnLastTwoCommands(): array Assert::fail('Not enough CommandStartedEvents observed'); } - public function assert(array $expectedEvents): void + public function assert(array $expectedEvents, bool $ignoreExtraEvents): void { - assertCount(count($expectedEvents), $this->actualEvents); + if ($ignoreExtraEvents) { + assertGreaterThanOrEqual(count($expectedEvents), count($this->actualEvents)); + } else { + assertCount(count($expectedEvents), $this->actualEvents); + } $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY); $mi->attachIterator(new ArrayIterator($expectedEvents)); @@ -215,6 +220,10 @@ public function assert(array $expectedEvents): void foreach ($mi as $keys => $events) { [$expectedEvent, $actualEvent] = $events; + if ($ignoreExtraEvents && $expectedEvent === null) { + break; + } + assertIsObject($expectedEvent); $expectedEvent = (array) $expectedEvent; assertCount(1, $expectedEvent); diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 939bedd22..b68a16a64 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -474,6 +474,12 @@ private function executeForCollection(Collection $collection) array_diff_key($args, ['map' => 1, 'reduce' => 1, 'out' => 1]) ); + case 'rename': + assertArrayHasKey('to', $args); + assertIsString($args['to']); + + return $collection->rename($args['to']); + default: Assert::fail('Unsupported collection operation: ' . $this->name); } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index f7275bf8b..404d2c238 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -21,6 +21,9 @@ class UnifiedSpecTest extends FunctionalTestCase { /** @var array */ private static $incompleteTests = [ + 'change-streams/change-streams: Test with document comment' => 'Not yet implemented (PHPLIB-749)', + 'change-streams/change-streams: Test with string comment' => 'Not yet implemented (PHPLIB-749)', + 'change-streams/change-streams: Test that comment is set on getMore' => 'Not yet implemented (PHPLIB-749)', 'command-monitoring/pre-42-server-connection-id: command events do not include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', 'command-monitoring/server-connection-id: command events include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', // Many load balancer tests use CMAP events and/or assertNumberConnectionsCheckedOut diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index def0a53dc..a49f878ef 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -50,7 +50,9 @@ final class UnifiedTestRunner public const SERVER_ERROR_UNAUTHORIZED = 13; public const MIN_SCHEMA_VERSION = '1.0'; - public const MAX_SCHEMA_VERSION = '1.5'; + + // Note: schema version 1.6 is not yet implemented (see: PHPLIB-718) + public const MAX_SCHEMA_VERSION = '1.7'; /** @var MongoDB\Client */ private $internalClient; diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index fd9ca40d4..2797cb50d 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -87,6 +87,7 @@ final class Util 'find' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'findOne' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'findOneAndReplace' => ['returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort'], + 'rename' => ['to'], 'replaceOne' => ['filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], 'findOneAndUpdate' => ['returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort'], 'updateMany' => ['filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json new file mode 100644 index 000000000..75faf8625 --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json @@ -0,0 +1,234 @@ +{ + "description": "change-streams-errors", + "schemaVersion": "1.7", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "killCursors" + ], + "useMultipleMongoses": false + } + }, + { + "client": { + "id": "globalClient", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "database": { + "id": "globalDatabase0", + "client": "globalClient", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "globalCollection0", + "database": "globalDatabase0", + "collectionName": "collection0" + } + } + ], + "tests": [ + { + "description": "The watch helper must not throw a custom exception when executed against a single server topology, but instead depend on a server error", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "single" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "expectError": { + "errorCode": 40573 + } + } + ] + }, + { + "description": "Change Stream should error when an invalid aggregation stage is passed in", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$unsupported": "foo" + } + ] + }, + "expectError": { + "errorCode": 40324 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + }, + { + "$unsupported": "foo" + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Change Stream should error when _id is projected out", + "runOnRequirements": [ + { + "minServerVersion": "4.1.11", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "_id": 0 + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "z": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectError": { + "errorCode": 280 + } + } + ] + }, + { + "description": "change stream errors on ElectionInProgress", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 216, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "z": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectError": { + "errorCode": 216 + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json new file mode 100644 index 000000000..167f4bb4b --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json @@ -0,0 +1,2347 @@ +{ + "description": "change-streams-resume-allowlist", + "schemaVersion": "1.7", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "killCursors" + ], + "useMultipleMongoses": false + } + }, + { + "client": { + "id": "globalClient", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "database": { + "id": "globalDatabase0", + "client": "globalClient", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "globalCollection0", + "database": "globalDatabase0", + "collectionName": "collection0" + } + } + ], + "tests": [ + { + "description": "change stream resumes after a network error", + "runOnRequirements": [ + { + "minServerVersion": "4.2" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "closeConnection": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after HostUnreachable", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 6, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after HostNotFound", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 7, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NetworkTimeout", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 89, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after ShutdownInProgress", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 91, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after PrimarySteppedDown", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 189, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after ExceededTimeLimit", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 262, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after SocketException", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 9001, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NotWritablePrimary", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 10107, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after InterruptedAtShutdown", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 11600, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after InterruptedDueToReplStateChange", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 11602, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NotPrimaryNoSecondaryOk", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 13435, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NotPrimaryOrSecondary", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 13436, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after StaleShardVersion", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 63, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after StaleEpoch", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 150, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after RetryChangeStream", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 234, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after FailedToSatisfyReadPreference", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 133, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after CursorNotFound", + "runOnRequirements": [ + { + "minServerVersion": "4.2" + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 43, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json new file mode 100644 index 000000000..68ea30587 --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json @@ -0,0 +1,2124 @@ +{ + "description": "change-streams-resume-errorlabels", + "schemaVersion": "1.7", + "runOnRequirements": [ + { + "minServerVersion": "4.3.1", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "killCursors" + ], + "useMultipleMongoses": false + } + }, + { + "client": { + "id": "globalClient", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "database": { + "id": "globalDatabase0", + "client": "globalClient", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "globalCollection0", + "database": "globalDatabase0", + "collectionName": "collection0" + } + } + ], + "tests": [ + { + "description": "change stream resumes after HostUnreachable", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 6, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after HostNotFound", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 7, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NetworkTimeout", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 89, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after ShutdownInProgress", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 91, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after PrimarySteppedDown", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 189, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after ExceededTimeLimit", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 262, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after SocketException", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 9001, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NotWritablePrimary", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 10107, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after InterruptedAtShutdown", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 11600, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after InterruptedDueToReplStateChange", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 11602, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NotPrimaryNoSecondaryOk", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 13435, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after NotPrimaryOrSecondary", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 13436, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after StaleShardVersion", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 63, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after StaleEpoch", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 150, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after RetryChangeStream", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 234, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes after FailedToSatisfyReadPreference", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failGetMoreAfterCursorCheckout", + "mode": { + "times": 1 + }, + "data": { + "errorCode": 133, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream resumes if error contains ResumableChangeStreamError", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 50, + "closeConnection": false, + "errorLabels": [ + "ResumableChangeStreamError" + ] + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$exists": true + }, + "collection": "collection0" + }, + "commandName": "getMore", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "resumeAfter": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "change stream does not resume if error does not contain ResumableChangeStreamError", + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "getMore" + ], + "errorCode": 6, + "closeConnection": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectError": { + "errorCode": 6 + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/change-streams/change-streams.json b/tests/UnifiedSpecTests/change-streams/change-streams.json index adaf00de2..eb8dd73af 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams.json @@ -1,10 +1,32 @@ { "description": "change-streams", - "schemaVersion": "1.0", + "schemaVersion": "1.7", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "topologies": [ + "replicaset", + "sharded-replicaset" + ] + } + ], "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "killCursors" + ], + "useMultipleMongoses": false + } + }, + { + "client": { + "id": "globalClient", + "useMultipleMongoses": false } }, { @@ -20,6 +42,62 @@ "database": "database0", "collectionName": "collection0" } + }, + { + "database": { + "id": "database1", + "client": "client0", + "databaseName": "database1" + } + }, + { + "collection": { + "id": "collection1", + "database": "database1", + "collectionName": "collection1" + } + }, + { + "database": { + "id": "globalDatabase0", + "client": "globalClient", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "globalCollection0", + "database": "globalDatabase0", + "collectionName": "collection0" + } + }, + { + "database": { + "id": "globalDatabase1", + "client": "globalClient", + "databaseName": "database1" + } + }, + { + "collection": { + "id": "globalCollection1", + "database": "globalDatabase1", + "collectionName": "collection1" + } + }, + { + "collection": { + "id": "globalDb1Collection0", + "database": "globalDatabase1", + "collectionName": "collection0" + } + }, + { + "collection": { + "id": "globalDb0Collection1", + "database": "globalDatabase0", + "collectionName": "collection1" + } } ], "initialData": [ @@ -34,10 +112,7 @@ "description": "Test array truncation", "runOnRequirements": [ { - "minServerVersion": "4.7", - "topologies": [ - "replicaset" - ] + "minServerVersion": "4.7" } ], "operations": [ @@ -111,6 +186,1595 @@ } } ] + }, + { + "description": "Test with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": { + "name": "test1" + } + }, + "saveResultAsEntity": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": { + "name": "test1" + } + } + } + } + ] + } + ] + }, + { + "description": "Test with document comment - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.2.99" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": { + "name": "test1" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": { + "name": "test1" + } + } + } + } + ] + } + ] + }, + { + "description": "Test with string comment", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": "comment" + }, + "saveResultAsEntity": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": "comment" + } + } + } + ] + } + ] + }, + { + "description": "Test that comment is set on getMore", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": { + "key": "value" + } + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": { + "key": "value" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "collection0", + "documents": [ + { + "_id": 1, + "a": 1 + } + ] + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "collection0", + "comment": { + "key": "value" + } + }, + "commandName": "getMore", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Test that comment is not set on getMore - pre 4.4", + "runOnRequirements": [ + { + "maxServerVersion": "4.3.99", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "comment": "comment" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "pipeline": [ + { + "$changeStream": {} + } + ], + "comment": "comment" + } + } + }, + { + "commandStartedEvent": { + "command": { + "insert": "collection0", + "documents": [ + { + "_id": 1, + "a": 1 + } + ] + } + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "collection0", + "comment": { + "$$exists": false + } + }, + "commandName": "getMore", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "to field is set in a rename change event", + "runOnRequirements": [ + { + "minServerVersion": "4.0.1" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "collection1" + } + }, + { + "name": "rename", + "object": "collection0", + "arguments": { + "to": "collection1" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "rename", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "to": { + "db": "database0", + "coll": "collection1" + } + } + } + ] + }, + { + "description": "Test unknown operationType MUST NOT err", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "operationType": "addedInFutureMongoDBVersion", + "ns": 1 + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "addedInFutureMongoDBVersion", + "ns": { + "db": "database0", + "coll": "collection0" + } + } + } + ] + }, + { + "description": "Test newField added in response MUST NOT err", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "operationType": 1, + "ns": 1, + "newField": "newFieldValue" + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "newField": "newFieldValue" + } + } + ] + }, + { + "description": "Test new structure in ns document MUST NOT err", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "operationType": "insert", + "ns.viewOn": "db.coll" + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "viewOn": "db.coll" + } + } + } + ] + }, + { + "description": "Test modified structure in ns document MUST NOT err", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "operationType": "insert", + "ns": { + "db": "$ns.db", + "coll": "$ns.coll", + "viewOn": "db.coll" + } + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0", + "viewOn": "db.coll" + } + } + } + ] + }, + { + "description": "Test server error on projecting out _id", + "runOnRequirements": [ + { + "minServerVersion": "4.2" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "_id": 0 + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectError": { + "errorCode": 280, + "errorCodeName": "ChangeStreamFatalError", + "errorLabelsContain": [ + "NonResumableChangeStreamError" + ] + } + } + ] + }, + { + "description": "Test projection in change stream returns expected fields", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "optype": "$operationType", + "ns": 1, + "newField": "value" + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "optype": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "newField": "value" + } + } + ] + }, + { + "description": "$changeStream must be the first stage in a change stream pipeline sent to the server", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "The server returns change stream responses in the specified server response format", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "_id": { + "$$exists": true + }, + "documentKey": { + "$$exists": true + }, + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + } + ] + }, + { + "description": "Executing a watch helper on a Collection results in notifications for changes to the specified collection", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalDb0Collection1", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "insertOne", + "object": "globalDb1Collection0", + "arguments": { + "document": { + "y": 2 + } + } + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "z": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "z": 3, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Change Stream should allow valid aggregate pipeline stages", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$match": { + "fullDocument.z": 3 + } + } + ] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "y": 2 + } + } + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "z": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "z": 3, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + }, + { + "$match": { + "fullDocument.z": 3 + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Executing a watch helper on a Database results in notifications for changes to all collections in the specified database.", + "runOnRequirements": [ + { + "minServerVersion": "3.8.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "database0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalDb0Collection1", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "insertOne", + "object": "globalDb1Collection0", + "arguments": { + "document": { + "y": 2 + } + } + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "z": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection1" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "z": 3, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Executing a watch helper on a MongoClient results in notifications for changes to all collections in all databases in the cluster.", + "runOnRequirements": [ + { + "minServerVersion": "3.8.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "client0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalDb0Collection1", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "insertOne", + "object": "globalDb1Collection0", + "arguments": { + "document": { + "y": 2 + } + } + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "z": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection1" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database1", + "coll": "collection0" + }, + "fullDocument": { + "y": 2, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "z": 3, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1, + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "allChangesForCluster": true + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "admin" + } + } + ] + } + ] + }, + { + "description": "Test insert, update, replace, and delete event types", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "updateOne", + "object": "globalCollection0", + "arguments": { + "filter": { + "x": 1 + }, + "update": { + "$set": { + "x": 2 + } + } + } + }, + { + "name": "replaceOne", + "object": "globalCollection0", + "arguments": { + "filter": { + "x": 2 + }, + "replacement": { + "x": 3 + } + } + }, + { + "name": "deleteOne", + "object": "globalCollection0", + "arguments": { + "filter": { + "x": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "updateDescription": { + "updatedFields": { + "x": 2 + }, + "removedFields": [], + "truncatedArrays": { + "$$unsetOrMatches": { + "$$exists": true + } + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "replace", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 3, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "delete", + "ns": { + "db": "database0", + "coll": "collection0" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Test rename and invalidate event types", + "runOnRequirements": [ + { + "minServerVersion": "4.0.1", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "collection1" + } + }, + { + "name": "rename", + "object": "globalCollection0", + "arguments": { + "to": "collection1" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "rename", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "to": { + "db": "database0", + "coll": "collection1" + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "invalidate" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Test drop and invalidate event types", + "runOnRequirements": [ + { + "minServerVersion": "4.0.1", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "collection0" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "drop", + "ns": { + "db": "database0", + "coll": "collection0" + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "invalidate" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "Test consecutive resume", + "runOnRequirements": [ + { + "minServerVersion": "4.1.7", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "globalClient", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "getMore" + ], + "closeConnection": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "batchSize": 1 + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 1 + } + } + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 2 + } + } + }, + { + "name": "insertOne", + "object": "globalCollection0", + "arguments": { + "document": { + "x": 3 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 1, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 2, + "_id": { + "$$exists": true + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "fullDocument": { + "x": 3, + "_id": { + "$$exists": true + } + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": { + "batchSize": 1 + }, + "pipeline": [ + { + "$changeStream": {} + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] } ] } diff --git a/tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-ignoreExtraEvents.json b/tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-ignoreExtraEvents.json new file mode 100644 index 000000000..178b756c2 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/expectedEventsForClient-ignoreExtraEvents.json @@ -0,0 +1,151 @@ +{ + "description": "expectedEventsForClient-ignoreExtraEvents", + "schemaVersion": "1.7", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": true, + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "ignoreExtraEvents can be set to false", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": false, + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 1 + } + ] + }, + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "ignoreExtraEvents can be set to true", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 2 + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 3 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 2 + } + ] + }, + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "ignoreExtraEvents defaults to false if unset", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 4 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": 4 + } + ] + }, + "commandName": "insert" + } + } + ] + } + ] + } + ] +} From 0bf583c9d1804001976272816cff495acd5f8f01 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Sat, 16 Apr 2022 12:54:26 -0400 Subject: [PATCH 130/321] Skip additional change stream "comment" tests (#914) --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 404d2c238..1e153264b 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -21,11 +21,6 @@ class UnifiedSpecTest extends FunctionalTestCase { /** @var array */ private static $incompleteTests = [ - 'change-streams/change-streams: Test with document comment' => 'Not yet implemented (PHPLIB-749)', - 'change-streams/change-streams: Test with string comment' => 'Not yet implemented (PHPLIB-749)', - 'change-streams/change-streams: Test that comment is set on getMore' => 'Not yet implemented (PHPLIB-749)', - 'command-monitoring/pre-42-server-connection-id: command events do not include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', - 'command-monitoring/server-connection-id: command events include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', // Many load balancer tests use CMAP events and/or assertNumberConnectionsCheckedOut 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: no connection is pinned if all documents are returned in the initial batch' => 'PHPC does not implement CMAP', 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: pinned connections are returned when the cursor is drained' => 'PHPC does not implement CMAP', @@ -64,6 +59,15 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType can be set to command and cmap' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType defaults to command if unset' => 'PHPC does not implement CMAP', + // Command monitoring event serverConnectionId is not yet implemented + 'command-monitoring/pre-42-server-connection-id: command events do not include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', + 'command-monitoring/server-connection-id: command events include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', + // Change stream "comment" option is not yet implemented + 'change-streams/change-streams: Test with document comment' => 'Not yet implemented (PHPLIB-749)', + 'change-streams/change-streams: Test with document comment - pre 4.4' => 'Not yet implemented (PHPLIB-749)', + 'change-streams/change-streams: Test with string comment' => 'Not yet implemented (PHPLIB-749)', + 'change-streams/change-streams: Test that comment is set on getMore' => 'Not yet implemented (PHPLIB-749)', + 'change-streams/change-streams: Test that comment is not set on getMore - pre 4.4' => 'Not yet implemented (PHPLIB-749)', // CRUD "comment" option is not yet implemented 'crud/bulkWrite-comment: BulkWrite with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/bulkWrite-comment: BulkWrite with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', From 9dd7886a0906180a2f758f3dcc4ab75643a12e9e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Sat, 16 Apr 2022 12:54:34 -0400 Subject: [PATCH 131/321] PHPLIB-844: Explicitly allow phpcodesniffer-composer-installer plugin (#915) --- composer.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/composer.json b/composer.json index 083182b24..91d8900d2 100644 --- a/composer.json +++ b/composer.json @@ -33,5 +33,10 @@ "branch-alias": { "dev-master": "1.13.x-dev" } + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } } From 452bc0fe66a8b615787ac477b2514220e6d88434 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Sat, 16 Apr 2022 20:05:12 +0300 Subject: [PATCH 132/321] PHPLIB-839: Update CSFLE spec tests for mongocryptd 6.0.0-alpha Synced with mongodb/specifications@6a7158d51b4c41f2f4a9c1293c5e1dceb93ab5c2 --- .../client-side-encryption/tests/badQueries.json | 4 ++-- .../client-side-encryption/tests/types.json | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/SpecTests/client-side-encryption/tests/badQueries.json b/tests/SpecTests/client-side-encryption/tests/badQueries.json index 824a53c00..4968307ba 100644 --- a/tests/SpecTests/client-side-encryption/tests/badQueries.json +++ b/tests/SpecTests/client-side-encryption/tests/badQueries.json @@ -1318,7 +1318,7 @@ } }, "result": { - "errorContains": "Cannot encrypt element of type array" + "errorContains": "Cannot encrypt element of type" } } ] @@ -1387,7 +1387,7 @@ } }, "result": { - "errorContains": "Cannot encrypt element of type array" + "errorContains": "Cannot encrypt element of type" } } ] diff --git a/tests/SpecTests/client-side-encryption/tests/types.json b/tests/SpecTests/client-side-encryption/tests/types.json index a070f8bff..a6c6507e9 100644 --- a/tests/SpecTests/client-side-encryption/tests/types.json +++ b/tests/SpecTests/client-side-encryption/tests/types.json @@ -504,7 +504,7 @@ } }, "result": { - "errorContains": "Cannot use deterministic encryption for element of type: double" + "errorContains": "element of type: double" } } ] @@ -551,7 +551,7 @@ } }, "result": { - "errorContains": "Cannot use deterministic encryption for element of type: decimal" + "errorContains": "element of type: decimal" } } ] @@ -883,7 +883,7 @@ } }, "result": { - "errorContains": "Cannot use deterministic encryption for element of type: javascriptWithScope" + "errorContains": "element of type: javascriptWithScope" } } ] @@ -928,7 +928,7 @@ } }, "result": { - "errorContains": "Cannot use deterministic encryption for element of type: object" + "errorContains": "element of type: object" } } ] @@ -1547,7 +1547,7 @@ } }, "result": { - "errorContains": "Cannot use deterministic encryption for element of type: array" + "errorContains": "element of type: array" } } ] @@ -1592,7 +1592,7 @@ } }, "result": { - "errorContains": "Cannot use deterministic encryption for element of type: bool" + "errorContains": "element of type: bool" } } ] From bf85cb98f2a1474521da2d84db95048590ba811c Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Mon, 18 Apr 2022 21:06:10 +0300 Subject: [PATCH 133/321] PHPLIB-748: Support 'let' option for multiple CRUD commands (#910) * Updating all necessary classes with new 'let' option support. * Adding actual tests from specifications for "let" option by syncing unified spec tests with https://github.com/mongodb/specifications/commit/1028c348c86bb2c0ea313c30ed8320825048fe5d * Updating tests skips as some features are not yet implemented. * Updating driver version requirements. * Updating Mongo docs. Co-authored-by: Jeremy Mikola --- .evergreen/config.yml | 14 ++++-- .github/workflows/coding-standards.yml | 2 +- .github/workflows/tests.yml | 8 ++-- composer.json | 2 +- ...oDBCollection-method-aggregate-option.yaml | 2 +- ...oDBCollection-method-bulkWrite-option.yaml | 6 +++ ...DBCollection-method-deleteMany-option.yaml | 6 +++ ...oDBCollection-method-deleteOne-option.yaml | 6 +++ ...-MongoDBCollection-method-find-option.yaml | 6 +++ ...ngoDBCollection-method-findOne-option.yaml | 6 +++ ...ection-method-findOneAndDelete-option.yaml | 6 +++ ...ction-method-findOneAndReplace-option.yaml | 6 +++ ...ection-method-findOneAndUpdate-option.yaml | 6 +++ ...DBCollection-method-replaceOne-option.yaml | 6 +++ ...DBCollection-method-updateMany-option.yaml | 6 +++ ...oDBCollection-method-updateOne-option.yaml | 6 +++ ...ngoDBDatabase-method-aggregate-option.yaml | 2 +- docs/includes/apiargs-aggregate-option.yaml | 14 ------ docs/includes/apiargs-common-option.yaml | 14 ++++++ src/Operation/BulkWrite.php | 13 ++++++ src/Operation/Delete.php | 27 +++++++++++- src/Operation/DeleteMany.php | 5 +++ src/Operation/DeleteOne.php | 5 +++ src/Operation/Find.php | 11 ++++- src/Operation/FindAndModify.php | 11 ++++- src/Operation/FindOne.php | 5 +++ src/Operation/FindOneAndDelete.php | 5 +++ src/Operation/FindOneAndReplace.php | 5 +++ src/Operation/FindOneAndUpdate.php | 5 +++ src/Operation/ReplaceOne.php | 5 +++ src/Operation/Update.php | 13 ++++++ src/Operation/UpdateMany.php | 5 +++ src/Operation/UpdateOne.php | 5 +++ tests/UnifiedSpecTests/UnifiedSpecTest.php | 43 ------------------- tests/UnifiedSpecTests/Util.php | 22 +++++----- 35 files changed, 226 insertions(+), 83 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 9ed418e1e..d93ec0152 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -591,14 +591,20 @@ axes: - id: driver-versions display_name: Driver Version values: + # TODO: Update to "1.14.0" once PHPC 1.14.0 is released - id: "oldest-supported" - display_name: "1.13.0" + # display_name: "1.14.0" + display_name: "1.14-dev (master)" variables: - EXTENSION_VERSION: "1.13.0" + # EXTENSION_VERSION: "1.14.0" + EXTENSION_BRANCH: "master" + # TODO: Update to "1.14.x"/"stable" once PHPC 1.14.0 is released - id: "latest-stable" - display_name: "1.13.x" + # display_name: "1.14.x" + display_name: "1.14-dev (master)" variables: - EXTENSION_VERSION: "stable" + # EXTENSION_VERSION: "stable" + EXTENSION_BRANCH: "master" - id: "latest-dev" display_name: "1.14-dev (master)" variables: diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 0a584a558..27f53b834 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -20,7 +20,7 @@ jobs: php-version: - "7.4" driver-version: - - "stable" + - "mongodb/mongo-php-driver@master" steps: - name: "Checkout" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dc6580c4f..dae42b290 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -27,24 +27,24 @@ jobs: mongodb-version: - "4.4" driver-version: - - "stable" + - "mongodb/mongo-php-driver@master" topology: - "server" include: - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "5.0" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "server" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "replica_set" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "4.4" - driver-version: "stable" + driver-version: "mongodb/mongo-php-driver@master" topology: "sharded_cluster" steps: diff --git a/composer.json b/composer.json index 91d8900d2..deab69b72 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.2 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.13.0", + "ext-mongodb": "^1.14.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, diff --git a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml index 1d0346daa..a2fc460d9 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml @@ -29,7 +29,7 @@ post: | .. versionadded:: 1.3 --- source: - file: apiargs-aggregate-option.yaml + file: apiargs-common-option.yaml ref: let post: | .. versionadded:: 1.9 diff --git a/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml index d5d2e5df4..7949954d6 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml @@ -2,6 +2,12 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: bypassDocumentValidation --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- arg_name: option name: ordered type: boolean diff --git a/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml index 55f6af9b3..b11e4f5f1 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml @@ -11,6 +11,12 @@ post: | .. versionadded:: 1.7 --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml index 55f6af9b3..b11e4f5f1 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml @@ -11,6 +11,12 @@ post: | .. versionadded:: 1.7 --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml index 7e298924d..e80f2365f 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml @@ -257,4 +257,10 @@ description: | interface: phpmethod operation: ~ optional: true +--- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml index 2371aabe2..139e700ac 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOne-option.yaml @@ -75,4 +75,10 @@ source: source: file: apiargs-MongoDBCollection-method-find-option.yaml ref: modifiers +--- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 ... diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml index c8a1e58ce..062700579 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml @@ -19,6 +19,12 @@ post: | .. versionadded:: 1.7 --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml index 2987f9b08..37f326cf0 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml @@ -27,6 +27,12 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: bypassDocumentValidation --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- arg_name: option name: returnDocument type: integer diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml index d3a6eff42..412125239 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml @@ -33,6 +33,12 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: bypassDocumentValidation --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- arg_name: option name: returnDocument type: integer diff --git a/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml index cfc3a71d4..dcd0847b8 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml @@ -19,6 +19,12 @@ post: | .. versionadded:: 1.6 --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml index b94cb750a..e102f5613 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml @@ -25,6 +25,12 @@ post: | .. versionadded:: 1.6 --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml index b94cb750a..e102f5613 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml @@ -25,6 +25,12 @@ post: | .. versionadded:: 1.6 --- +source: + file: apiargs-common-option.yaml + ref: let +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml index 4d0bf4b25..f24d99d2c 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml @@ -23,7 +23,7 @@ source: ref: hint --- source: - file: apiargs-aggregate-option.yaml + file: apiargs-common-option.yaml ref: let post: | .. versionadded:: 1.9 diff --git a/docs/includes/apiargs-aggregate-option.yaml b/docs/includes/apiargs-aggregate-option.yaml index 557cd98fb..77d6d535e 100644 --- a/docs/includes/apiargs-aggregate-option.yaml +++ b/docs/includes/apiargs-aggregate-option.yaml @@ -45,18 +45,4 @@ description: | interface: phpmethod operation: ~ optional: true ---- -arg_name: option -name: let -type: array|object -description: | - Map of parameter names and values. Values must be constant or closed - expressions that do not reference document fields. Parameters can then be - accessed as variables in an aggregate expression context (e.g. ``$$var``). - - This is not supported for server versions prior to 5.0 and will result in an - exception at execution time if used. -interface: phpmethod -operation: ~ -optional: true ... diff --git a/docs/includes/apiargs-common-option.yaml b/docs/includes/apiargs-common-option.yaml index 6ef2c761e..667b35bdb 100644 --- a/docs/includes/apiargs-common-option.yaml +++ b/docs/includes/apiargs-common-option.yaml @@ -24,6 +24,20 @@ operation: ~ optional: true --- arg_name: option +name: let +type: array|object +description: | + Map of parameter names and values. Values must be constant or closed + expressions that do not reference document fields. Parameters can then be + accessed as variables in an aggregate expression context (e.g. ``$$var``). + + This is not supported for server versions prior to 5.0 and will result in an + exception at execution time if used. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: maxTimeMS type: integer description: | diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index dd898cc2b..e80c562b5 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -107,6 +107,11 @@ class BulkWrite implements Executable * performing the remaining writes. If false, when a write fails, * continue with the remaining writes, if any. The default is true. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * session (MongoDB\Driver\Session): Client session. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. @@ -275,6 +280,10 @@ public function __construct($databaseName, $collectionName, array $operations, a throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { + throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { unset($options['bypassDocumentValidation']); } @@ -348,6 +357,10 @@ private function createBulkWriteOptions() $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; } + if (isset($this->options['let'])) { + $options['let'] = (object) $this->options['let']; + } + return $options; } diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index fb60d09a5..a52d45bdf 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -75,6 +75,11 @@ class Delete implements Executable, Explainable * This is not supported for server versions < 4.4 and will result in an * exception at execution time if used. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * session (MongoDB\Driver\Session): Client session. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. @@ -114,6 +119,10 @@ public function __construct($databaseName, $collectionName, $filter, $limit, arr throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { + throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + } + if (isset($options['writeConcern']) && $options['writeConcern']->isDefault()) { unset($options['writeConcern']); } @@ -150,7 +159,7 @@ public function execute(Server $server) throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - $bulk = new Bulk(); + $bulk = new Bulk($this->createBulkWriteOptions()); $bulk->delete($this->filter, $this->createDeleteOptions()); $writeResult = $server->executeBulkWrite($this->databaseName . '.' . $this->collectionName, $bulk, $this->createExecuteOptions()); @@ -176,6 +185,22 @@ public function getCommandDocument(Server $server) return $cmd; } + /** + * Create options for constructing the bulk write. + * + * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php + */ + private function createBulkWriteOptions(): array + { + $options = []; + + if (isset($this->options['let'])) { + $options['let'] = (object) $this->options['let']; + } + + return $options; + } + /** * Create options for the delete command. * diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index 0e43ff889..d72c22ab7 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -49,6 +49,11 @@ class DeleteMany implements Executable, Explainable * This is not supported for server versions < 4.4 and will result in an * exception at execution time if used. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * session (MongoDB\Driver\Session): Client session. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index 1f797b0c9..91b47954e 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -49,6 +49,11 @@ class DeleteOne implements Executable, Explainable * This is not supported for server versions < 4.4 and will result in an * exception at execution time if used. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * session (MongoDB\Driver\Session): Client session. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. diff --git a/src/Operation/Find.php b/src/Operation/Find.php index f3bff9e02..5371243dd 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -145,6 +145,11 @@ class Find implements Executable, Explainable * "$orderby" also exists in the modifiers document, this option will * take precedence. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * typeMap (array): Type map for BSON deserialization. This will be * applied to the returned Cursor (it is not sent to the server). * @@ -274,6 +279,10 @@ public function __construct($databaseName, $collectionName, $filter, array $opti throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); } + if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { + throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + } + if (isset($options['readConcern']) && $options['readConcern']->isDefault()) { unset($options['readConcern']); } @@ -420,7 +429,7 @@ private function createQueryOptions() } } - foreach (['collation', 'max', 'min'] as $option) { + foreach (['collation', 'let', 'max', 'min'] as $option) { if (isset($this->options[$option])) { $options[$option] = (object) $this->options[$option]; } diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index eb0aa3169..c99acc1c7 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -113,6 +113,11 @@ class FindAndModify implements Executable, Explainable * matches the query. This option is ignored for remove operations. The * default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name @@ -184,6 +189,10 @@ public function __construct($databaseName, $collectionName, array $options) throw InvalidArgumentException::invalidType('"upsert" option', $options['upsert'], 'boolean'); } + if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { + throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { unset($options['bypassDocumentValidation']); } @@ -277,7 +286,7 @@ private function createCommandDocument() } } - foreach (['collation', 'fields', 'query', 'sort'] as $option) { + foreach (['collation', 'fields', 'let', 'query', 'sort'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = (object) $this->options[$option]; } diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index 0193b389e..de46314ef 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -89,6 +89,11 @@ class FindOne implements Executable, Explainable * "$orderby" also exists in the modifiers document, this option will * take precedence. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * typeMap (array): Type map for BSON deserialization. * * @param string $databaseName Database name diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 4c31977d3..9f27d30d4 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -62,6 +62,11 @@ class FindOneAndDelete implements Executable, Explainable * * sort (document): Determines which document the operation modifies if * the query selects multiple documents. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * typeMap (array): Type map for BSON deserialization. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 999a3eef5..879569bfc 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -82,6 +82,11 @@ class FindOneAndReplace implements Executable, Explainable * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index 5cbf1ad33..4951f4d0f 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -86,6 +86,11 @@ class FindOneAndUpdate implements Executable, Explainable * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index 6285bc738..667813775 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -62,6 +62,11 @@ class ReplaceOne implements Executable * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 3081591f0..5219ce4bb 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -93,6 +93,11 @@ class Update implements Executable, Explainable * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name @@ -154,6 +159,10 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } + if (isset($options['let']) && ! is_array($options['let']) && ! is_object($options['let'])) { + throw InvalidArgumentException::invalidType('"let" option', $options['let'], 'array or object'); + } + if (isset($options['bypassDocumentValidation']) && ! $options['bypassDocumentValidation']) { unset($options['bypassDocumentValidation']); } @@ -238,6 +247,10 @@ private function createBulkWriteOptions() $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; } + if (isset($this->options['let'])) { + $options['let'] = (object) $this->options['let']; + } + return $options; } diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index f63d4cbab..9db83e629 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -65,6 +65,11 @@ class UpdateMany implements Executable, Explainable * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index 699516595..ee8a2c32d 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -65,6 +65,11 @@ class UpdateOne implements Executable, Explainable * * upsert (boolean): When true, a new document is created if no document * matches the query. The default is false. * + * * let (document): Map of parameter names and values. Values must be + * constant or closed expressions that do not reference document fields. + * Parameters can then be accessed as variables in an aggregate + * expression context (e.g. "$$var"). + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @param string $databaseName Database name diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 1e153264b..5db237cbb 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -109,49 +109,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - // CRUD "let" option is not yet implemented - 'crud/BulkWrite deleteMany-let: BulkWrite deleteMany-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite deleteMany-let: BulkWrite deleteMany with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite deleteMany-let: BulkWrite deleteMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite deleteOne-let: BulkWrite deleteOne-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite deleteOne-let: BulkWrite deleteOne with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite deleteOne-let: BulkWrite deleteOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite replaceOne-let: BulkWrite replaceOne-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite replaceOne-let: BulkWrite replaceOne with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite replaceOne-let: BulkWrite replaceOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite updateMany-let: BulkWrite updateMany-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite updateMany-let: BulkWrite updateMany with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite updateMany-let: BulkWrite updateMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite updateOne-let: BulkWrite updateOne-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite updateOne-let: BulkWrite updateOne with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/BulkWrite updateOne-let: BulkWrite updateOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/deleteMany-let: deleteMany-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/deleteMany-let: deleteMany with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/deleteMany-let: deleteMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/deleteOne-let: deleteOne-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/deleteOne-let: deleteOne with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/deleteOne-let: deleteOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/find-let: find-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/find-let: Find with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/find-let: Find with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndDelete-let: findOneAndDelete-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndDelete-let: findOneAndDelete with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndDelete-let: findOneAndDelete with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndReplace-let: findOneAndReplace-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndReplace-let: findOneAndReplace with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndReplace-let: findOneAndReplace with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndUpdate-let: findOneAndUpdate-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndUpdate-let: findOneAndUpdate with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/findOneAndUpdate-let: findOneAndUpdate with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/replaceOne-let: replaceOne-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/replaceOne-let: ReplaceOne with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/replaceOne-let: ReplaceOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/updateMany-let: updateMany-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/updateMany-let: updateMany with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/updateMany-let: updateMany with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', - 'crud/updateOne-let: updateOne-let' => 'Not yet implemented (PHPLIB-748)', - 'crud/updateOne-let: UpdateOne with let option' => 'Not yet implemented (PHPLIB-748)', - 'crud/updateOne-let: UpdateOne with let option unsupported (server-side error)' => 'Not yet implemented (PHPLIB-748)', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 2797cb50d..191f42fb9 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -71,7 +71,7 @@ final class Util ], Collection::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], - 'bulkWrite' => ['requests', 'session', 'ordered', 'bypassDocumentValidation'], + 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation'], 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session'], @@ -79,19 +79,19 @@ final class Util 'count' => ['filter', 'session', 'collation', 'hint', 'limit', 'maxTimeMS', 'skip'], 'countDocuments' => ['filter', 'session', 'limit', 'skip', 'collation', 'hint', 'maxTimeMS'], 'estimatedDocumentCount' => ['session', 'maxTimeMS'], - 'deleteMany' => ['filter', 'session', 'collation', 'hint'], - 'deleteOne' => ['filter', 'session', 'collation', 'hint'], - 'findOneAndDelete' => ['filter', 'session', 'projection', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'sort', 'update', 'upsert'], + 'deleteMany' => ['let', 'filter', 'session', 'collation', 'hint'], + 'deleteOne' => ['let', 'filter', 'session', 'collation', 'hint'], + 'findOneAndDelete' => ['let', 'filter', 'session', 'projection', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'sort', 'update', 'upsert'], 'distinct' => ['fieldName', 'filter', 'session', 'collation', 'maxTimeMS'], 'drop' => ['session'], - 'find' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], - 'findOne' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], - 'findOneAndReplace' => ['returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort'], + 'find' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'findOne' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], + 'findOneAndReplace' => ['let', 'returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort'], 'rename' => ['to'], - 'replaceOne' => ['filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], - 'findOneAndUpdate' => ['returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort'], - 'updateMany' => ['filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], - 'updateOne' => ['filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], + 'replaceOne' => ['let', 'filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], + 'findOneAndUpdate' => ['let', 'returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort'], + 'updateMany' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], + 'updateOne' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], 'insertMany' => ['options', 'documents', 'session', 'ordered', 'bypassDocumentValidation'], 'insertOne' => ['document', 'session', 'bypassDocumentValidation'], 'listIndexes' => ['session', 'maxTimeMS'], From c1ecab9246a4493eb85fcfb120c5eaf1bf042312 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Mon, 18 Apr 2022 22:51:23 +0300 Subject: [PATCH 134/321] PHPLIB-826: Remove use of admin database in CSFLE driver doc examples --- docs/tutorial/client-side-encryption.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/tutorial/client-side-encryption.txt b/docs/tutorial/client-side-encryption.txt index cc77b07b1..184bcc07c 100644 --- a/docs/tutorial/client-side-encryption.txt +++ b/docs/tutorial/client-side-encryption.txt @@ -35,7 +35,7 @@ encrypted on insertion and decrypted when querying on the client side. $localKey = new Binary('', Binary::TYPE_GENERIC); $encryptionOpts = [ - 'keyVaultNamespace' => 'admin.datakeys', + 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], @@ -101,7 +101,7 @@ encryption using the newly created key. $localKey = new Binary('', Binary::TYPE_GENERIC); $clientEncryptionOpts = [ - 'keyVaultNamespace' => 'admin.datakeys', + 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], @@ -114,7 +114,7 @@ encryption using the newly created key. $keyId = $clientEncryption->createDataKey('local'); $autoEncryptionOpts = [ - 'keyVaultNamespace' => 'admin.datakeys', + 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], @@ -163,7 +163,7 @@ explicitly encrypts and decrypts values in the document. $localKey = new Binary('', Binary::TYPE_GENERIC); $clientEncryptionOpts = [ - 'keyVaultNamespace' => 'admin.datakeys', + 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], @@ -212,7 +212,7 @@ The software then encrypts data by referencing the key by its alternative name. $localKey = new Binary('', Binary::TYPE_GENERIC); $clientEncryptionOpts = [ - 'keyVaultNamespace' => 'admin.datakeys', + 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ 'local' => ['key' => $localKey], ], From 2a9f2f08b487fff895252ccab21dbf00543315f0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 19 Apr 2022 11:10:58 -0400 Subject: [PATCH 135/321] PHPLIB-810: Temporarily skip stable API count test for server 6.0+ (#918) This test expects an exception executing count via the stable API; however, 6.0.0-rc0 added count to the stable API so an exception is no longer raised. Driver changes are not yet specified but we can skip this test in the meantime. --- tests/DocumentationExamplesTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index b4beb1b39..ffe345d6f 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1723,6 +1723,10 @@ public function testVersionedApiMigration(): void $this->markTestSkipped('Versioned API is not supported'); } + if (version_compare($this->getServerVersion(), '5.9', '>=')) { + $this->markTestIncomplete('SERVER-63850 added count command to API version 1 in MongoDB 6.0.0-rc0 (see: PHPLIB-810)'); + } + $uriString = static::getUri(true); // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly From 2704fb05e3a96cc63544c2f6e0c33008740b6915 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 20 Apr 2022 12:00:49 -0400 Subject: [PATCH 136/321] PHPLIB-814: Change stream support for point-in-time pre and post-images (#911) Introduces fullDocumentBeforeChange option. Tests for specifying "whenAvailable" and "required" for both fullDocument and fullDocumentBeforeChange (requires MongoDB 6.0+ with changeStreamPreAndPostImages enabled on the collection). Intentionally omits mention of FULL_DOCUMENT_DEFAULT (related to PHPLIB-808) and FULL_DOCUMENT_BEFORE_CHANGE_OFF constants, since those redundantly specified default behavior. Tests synced with mongodb/specifications@89788990924ac3bfe43586233dd4f0159e2bf9b9 --- ...rgs-MongoDBClient-method-watch-option.yaml | 6 + ...MongoDBCollection-method-watch-option.yaml | 6 + ...s-MongoDBDatabase-method-watch-option.yaml | 6 + .../includes/apiargs-method-watch-option.yaml | 51 +- src/Operation/Watch.php | 46 +- tests/Operation/WatchTest.php | 4 + tests/UnifiedSpecTests/Util.php | 2 +- .../change-streams-pre_and_post_images.json | 826 ++++++++++++++++++ 8 files changed, 931 insertions(+), 16 deletions(-) create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json diff --git a/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml b/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml index 2dd040e95..7fa5400a8 100644 --- a/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml @@ -11,6 +11,12 @@ source: file: apiargs-method-watch-option.yaml ref: fullDocument --- +source: + file: apiargs-method-watch-option.yaml + ref: fullDocumentBeforeChange +post: | + .. versionadded: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: maxAwaitTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml index a873beec5..d785b471e 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml @@ -11,6 +11,12 @@ source: file: apiargs-method-watch-option.yaml ref: fullDocument --- +source: + file: apiargs-method-watch-option.yaml + ref: fullDocumentBeforeChange +post: | + .. versionadded: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: maxAwaitTimeMS diff --git a/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml index b1ad02793..7de7df6d2 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml @@ -11,6 +11,12 @@ source: file: apiargs-method-watch-option.yaml ref: fullDocument --- +source: + file: apiargs-method-watch-option.yaml + ref: fullDocumentBeforeChange +post: | + .. versionadded: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: maxAwaitTimeMS diff --git a/docs/includes/apiargs-method-watch-option.yaml b/docs/includes/apiargs-method-watch-option.yaml index 89887884f..00aba3135 100644 --- a/docs/includes/apiargs-method-watch-option.yaml +++ b/docs/includes/apiargs-method-watch-option.yaml @@ -13,14 +13,53 @@ arg_name: option name: fullDocument type: string description: | - Allowed values are 'default' and 'updateLookup'. Defaults to 'default'. - When set to 'updateLookup', the change notification for partial updates will - include both a delta describing the changes to the document, as well as a - copy of the entire document that was changed from some time after the change - occurred. The following values are supported: + Determines how the "fullDocument" response field will be populated for update + operations. + + By default, change streams only return the delta of fields (via an + "udateDescription" field) for update operations and "fullDocument" is omitted. + Insert and replace operations always include the "fullDocument" field. Delete + operations omit the field as the document no longer exists. + + Specify "updateLookup" to return the current majority-committed version of the + updated document. + + MongoDB 6.0+ allows returning the post-image of the modified document if the + collection has ``changeStreamPreAndPostImages`` enabled. Specify + "whenAvailable" to return the post-image if available or a null value if not. + Specify "required" to return the post-image if available or raise an error if + not. + + The following values are supported: - - ``MongoDB\Operation\Watch::FULL_DOCUMENT_DEFAULT`` (*default*) - ``MongoDB\Operation\Watch::FULL_DOCUMENT_UPDATE_LOOKUP`` + - ``MongoDB\Operation\Watch::FULL_DOCUMENT_WHEN_AVAILABLE`` + - ``MongoDB\Operation\Watch::FULL_DOCUMENT_REQUIRED`` + + .. note:: + + This is an option of the ``$changeStream`` pipeline stage. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option +name: fullDocumentBeforeChange +type: string +description: | + Determines how the "fullDocumentBeforeChange" response field will be + populated. By default, the field is omitted. + + MongoDB 6.0+ allows returning the pre-image of the modified document if the + collection has ``changeStreamPreAndPostImages`` enabled. Specify + "whenAvailable" to return the pre-image if available or a null value if not. + Specify "required" to return the pre-image if available or raise an error if + not. + + The following values are supported: + + - ``MongoDB\Operation\Watch::FULL_DOCUMENT_BEFORE_CHANGE_WHEN_AVAILABLE`` + - ``MongoDB\Operation\Watch::FULL_DOCUMENT_BEFORE_CHANGE_REQUIRED`` .. note:: diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 3b4927ce3..2e852941a 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -59,6 +59,12 @@ class Watch implements Executable, /* @internal */ CommandSubscriber { public const FULL_DOCUMENT_DEFAULT = 'default'; public const FULL_DOCUMENT_UPDATE_LOOKUP = 'updateLookup'; + public const FULL_DOCUMENT_WHEN_AVAILABLE = 'whenAvailable'; + public const FULL_DOCUMENT_REQUIRED = 'required'; + + public const FULL_DOCUMENT_BEFORE_CHANGE_OFF = 'off'; + public const FULL_DOCUMENT_BEFORE_CHANGE_WHEN_AVAILABLE = 'whenAvailable'; + public const FULL_DOCUMENT_BEFORE_CHANGE_REQUIRED = 'required'; /** @var integer */ private static $wireVersionForStartAtOperationTime = 7; @@ -105,15 +111,33 @@ class Watch implements Executable, /* @internal */ CommandSubscriber * * * collation (document): Specifies a collation. * - * * fullDocument (string): Determines whether the "fullDocument" field - * will be populated for update operations. By default, change streams - * only return the delta of fields during the update operation (via the - * "updateDescription" field). To additionally return the most current - * majority-committed version of the updated document, specify - * "updateLookup" for this option. Defaults to "default". + * * fullDocument (string): Determines how the "fullDocument" response + * field will be populated for update operations. + * + * By default, change streams only return the delta of fields (via an + * "updateDescription" field) for update operations and "fullDocument" is + * omitted. Insert and replace operations always include the + * "fullDocument" field. Delete operations omit the field as the document + * no longer exists. + * + * Specify "updateLookup" to return the current majority-committed + * version of the updated document. + * + * MongoDB 6.0+ allows returning the post-image of the modified document + * if the collection has changeStreamPreAndPostImages enabled. Specify + * "whenAvailable" to return the post-image if available or a null value + * if not. Specify "required" to return the post-image if available or + * raise an error if not. * - * Insert and replace operations always include the "fullDocument" field - * and delete operations omit the field as the document no longer exists. + * * fullDocumentBeforeChange (string): Determines how the + * "fullDocumentBeforeChange" response field will be populated. By + * default, the field is omitted. + * + * MongoDB 6.0+ allows returning the pre-image of the modified document + * if the collection has changeStreamPreAndPostImages enabled. Specify + * "whenAvailable" to return the pre-image if available or a null value + * if not. Specify "required" to return the pre-image if available or + * raise an error if not. * * * maxAwaitTimeMS (integer): The maximum amount of time for the server to * wait on new documents to satisfy a change stream query. @@ -181,6 +205,10 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar throw InvalidArgumentException::invalidType('"fullDocument" option', $options['fullDocument'], 'string'); } + if (isset($options['fullDocumentBeforeChange']) && ! is_string($options['fullDocumentBeforeChange'])) { + throw InvalidArgumentException::invalidType('"fullDocumentBeforeChange" option', $options['fullDocumentBeforeChange'], 'string'); + } + if (! $options['readPreference'] instanceof ReadPreference) { throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class); } @@ -212,7 +240,7 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } $this->aggregateOptions = array_intersect_key($options, ['batchSize' => 1, 'collation' => 1, 'maxAwaitTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1, 'typeMap' => 1]); - $this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'resumeAfter' => 1, 'startAfter' => 1, 'startAtOperationTime' => 1]); + $this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'fullDocumentBeforeChange' => 1, 'resumeAfter' => 1, 'startAfter' => 1, 'startAtOperationTime' => 1]); // Null database name implies a cluster-wide change stream if ($databaseName === null) { diff --git a/tests/Operation/WatchTest.php b/tests/Operation/WatchTest.php index ba790fb5f..d4d1be19c 100644 --- a/tests/Operation/WatchTest.php +++ b/tests/Operation/WatchTest.php @@ -56,6 +56,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['fullDocument' => $value]; } + foreach ($this->getInvalidStringValues() as $value) { + $options[][] = ['fullDocumentBeforeChange' => $value]; + } + foreach ($this->getInvalidIntegerValues() as $value) { $options[][] = ['maxAwaitTimeMS' => $value]; } diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 191f42fb9..c7fc7f559 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -72,7 +72,7 @@ final class Util Collection::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation'], - 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session'], 'dropIndex' => ['name', 'session', 'maxTimeMS'], diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json b/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json new file mode 100644 index 000000000..b6f0e2c3b --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json @@ -0,0 +1,826 @@ +{ + "description": "change-streams-pre_and_post_images", + "schemaVersion": "1.0", + "runOnRequirements": [ + { + "minServerVersion": "6.0.0", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "collMod", + "insert", + "update", + "getMore", + "killCursors" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "change-stream-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "change-stream-tests", + "documents": [ + { + "_id": 1 + } + ] + } + ], + "tests": [ + { + "description": "fullDocument:whenAvailable with changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocument": "whenAvailable" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocument": { + "_id": 1, + "x": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocument": "whenAvailable" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocument:whenAvailable with changeStreamPreAndPostImages disabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocument": "whenAvailable" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocument": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocument": "whenAvailable" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocument:required with changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocument": "required" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocument": { + "_id": 1, + "x": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocument": "required" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocument:required with changeStreamPreAndPostImages disabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocument": "required" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocument": "required" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocumentBeforeChange:whenAvailable with changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocumentBeforeChange": "whenAvailable" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocumentBeforeChange": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocumentBeforeChange": "whenAvailable" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocumentBeforeChange:whenAvailable with changeStreamPreAndPostImages disabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocumentBeforeChange": "whenAvailable" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocumentBeforeChange": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocumentBeforeChange": "whenAvailable" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocumentBeforeChange:required with changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocumentBeforeChange": "required" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocumentBeforeChange": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocumentBeforeChange": "required" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocumentBeforeChange:required with changeStreamPreAndPostImages disabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocumentBeforeChange": "required" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocumentBeforeChange": "required" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocumentBeforeChange:off with changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocumentBeforeChange": "off" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocumentBeforeChange": { + "$$exists": false + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocumentBeforeChange": "off" + } + } + ] + } + } + } + ] + } + ] + }, + { + "description": "fullDocumentBeforeChange:off with changeStreamPreAndPostImages disabled", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collMod", + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "fullDocumentBeforeChange": "off" + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "change-stream-tests", + "coll": "test" + }, + "updateDescription": { + "$$type": "object" + }, + "fullDocumentBeforeChange": { + "$$exists": false + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "test", + "pipeline": [ + { + "$changeStream": { + "fullDocumentBeforeChange": "off" + } + } + ] + } + } + } + ] + } + ] + } + ] +} From 145d4f5bf50595b87f2f3640f896405c4f49d734 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 22 Apr 2022 14:29:58 -0400 Subject: [PATCH 137/321] PHPLIB-652: Update change stream error tests for 3.6 compat (#920) Synced with mongodb/specifications@dbfbc0f4f10234b1fa4f3f216b0919c68e4607bb --- .../change-streams/change-streams-errors.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json index 75faf8625..c0a9b3f09 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json @@ -49,6 +49,13 @@ } } ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [] + } + ], "tests": [ { "description": "The watch helper must not throw a custom exception when executed against a single server topology, but instead depend on a server error", From 52788f4d3f562ca43e7be47db53da09657fa6aa9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 26 Apr 2022 12:44:28 -0400 Subject: [PATCH 138/321] PHPLIB-757: Serverless testing uses LB with single proxy (#919) * PHPLIB-757: Serverless testing uses LB with single proxy * PHPLIB-850: Forbid serverless for unified change stream tests Synced with mongodb/specifications@08a07f62fd9d857f72de21cad4dcde63144ce12b --- .evergreen/config.yml | 9 +- tests/UnifiedSpecTests/Context.php | 100 +++++------------- tests/UnifiedSpecTests/UnifiedTestRunner.php | 79 +++++++++++++- .../change-streams/change-streams-errors.json | 5 + .../change-streams-pre_and_post_images.json | 5 +- .../change-streams-resume-allowlist.json | 3 +- .../change-streams-resume-errorLabels.json | 3 +- .../change-streams/change-streams.json | 3 +- .../valid-pass/poc-change-streams.json | 7 +- 9 files changed, 124 insertions(+), 90 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index d93ec0152..9435849de 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -92,7 +92,7 @@ functions: # If this was a patch build, doing a fresh clone would not actually test the patch cp -R ${PROJECT_DIRECTORY}/ $DRIVERS_TOOLS else - git clone https://github.com/mongodb-labs/drivers-evergreen-tools.git $DRIVERS_TOOLS + git clone https://github.com/mongodb-labs/drivers-evergreen-tools.git --depth 1 $DRIVERS_TOOLS fi echo "{ \"releases\": { \"default\": \"$MONGODB_BINARIES\" }}" > $MONGO_ORCHESTRATION_HOME/orchestration.config @@ -205,7 +205,6 @@ functions: working_dir: "src" script: | ${PREPARE_SHELL} - LOADBALANCED=ON \ SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \ SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \ SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \ @@ -220,10 +219,10 @@ functions: script: | # Only run if a serverless instance was started if [ -n "${SERVERLESS_INSTANCE_NAME}" ]; then + SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} \ SERVERLESS_DRIVERS_GROUP=${SERVERLESS_DRIVERS_GROUP} \ SERVERLESS_API_PUBLIC_KEY=${SERVERLESS_API_PUBLIC_KEY} \ SERVERLESS_API_PRIVATE_KEY=${SERVERLESS_API_PRIVATE_KEY} \ - SERVERLESS_INSTANCE_NAME=${SERVERLESS_INSTANCE_NAME} \ bash ${DRIVERS_TOOLS}/.evergreen/serverless/delete-instance.sh fi @@ -271,7 +270,7 @@ functions: export MONGODB_USERNAME=${SERVERLESS_ATLAS_USER} export MONGODB_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} export PATH="${PHP_PATH}/bin:$PATH" - PHP_VERSION=${PHP_VERSION} TESTS="serverless" MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + PHP_VERSION=${PHP_VERSION} TESTS="serverless" MONGODB_URI="${SERVERLESS_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "cleanup": - command: shell.exec @@ -491,8 +490,6 @@ tasks: commands: - func: "create serverless instance" - func: "run serverless tests" - vars: - MONGODB_URI: "${SINGLE_ATLASPROXY_SERVERLESS_URI}" - name: "test-loadBalanced" tags: ["loadbalanced"] diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 27214aae7..7ac1b81f8 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -4,8 +4,6 @@ use LogicException; use MongoDB\Client; -use MongoDB\Driver\ReadPreference; -use MongoDB\Driver\Server; use MongoDB\Driver\ServerApi; use MongoDB\Model\BSONArray; use MongoDB\Tests\FunctionalTestCase; @@ -13,12 +11,9 @@ use function array_key_exists; use function array_map; -use function count; use function current; use function explode; -use function implode; use function key; -use function parse_url; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertCount; use function PHPUnit\Framework\assertIsArray; @@ -27,16 +22,8 @@ use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertNotEmpty; -use function PHPUnit\Framework\assertNotFalse; use function PHPUnit\Framework\assertNotSame; use function PHPUnit\Framework\assertSame; -use function PHPUnit\Framework\assertStringContainsString; -use function PHPUnit\Framework\assertStringStartsWith; -use function strlen; -use function strpos; -use function substr_replace; - -use const PHP_URL_HOST; /** * Execution context for spec tests. @@ -67,11 +54,34 @@ final class Context /** @var string */ private $uri; + /** @var string */ + private $singleMongosUri; + + /** @var string */ + private $multiMongosUri; + public function __construct(Client $internalClient, string $uri) { $this->entityMap = new EntityMap(); $this->internalClient = $internalClient; $this->uri = $uri; + + /* TODO: Consider leaving these unset, although that might require + * redundant topology/serverless checks in Context::createClient(). */ + $this->singleMongosUri = $uri; + $this->multiMongosUri = $uri; + } + + /** + * Set single and multi-mongos URIs for useMultipleMongoses. This should be + * called for sharded cluster and non-serverless load balanced topologies. + * + * @see UnifiedTestRunner::createContext() + */ + public function setUrisForUseMultipleMongoses(string $singleMongosUri, string $multiMongosUri): void + { + $this->singleMongosUri = $singleMongosUri; + $this->multiMongosUri = $multiMongosUri; } /** @@ -254,11 +264,7 @@ private function createClient(string $id, stdClass $o): void if (isset($useMultipleMongoses)) { assertIsBool($useMultipleMongoses); - if ($useMultipleMongoses) { - self::requireMultipleMongoses($uri); - } else { - $uri = self::removeMultipleMongoses($uri); - } + $uri = $useMultipleMongoses ? $this->multiMongosUri : $this->singleMongosUri; } $uriOptions = []; @@ -461,62 +467,4 @@ private static function prepareDefaultTransactionOptions(array $options): array return Util::prepareCommonOptions($options); } - - /** - * Removes mongos hosts beyond the first if the URI refers to a sharded - * cluster. Otherwise, the URI is returned as-is. - */ - private static function removeMultipleMongoses(string $uri): string - { - assertStringStartsWith('mongodb://', $uri); - - $manager = FunctionalTestCase::createTestManager($uri); - - // Nothing to do if the URI does not refer to a sharded cluster - if ($manager->selectServer(new ReadPreference(ReadPreference::PRIMARY))->getType() !== Server::TYPE_MONGOS) { - return $uri; - } - - $parts = parse_url($uri); - - assertIsArray($parts); - - $hosts = explode(',', $parts['host']); - - // Nothing to do if the URI already has a single mongos host - if (count($hosts) === 1) { - return $uri; - } - - // Re-append port to last host - if (isset($parts['port'])) { - $hosts[count($hosts) - 1] .= ':' . $parts['port']; - } - - $singleHost = $hosts[0]; - $multipleHosts = implode(',', $hosts); - - $pos = strpos($uri, $multipleHosts); - - assertNotFalse($pos); - - return substr_replace($uri, $singleHost, $pos, strlen($multipleHosts)); - } - - /** - * Requires multiple mongos hosts if the URI refers to a sharded cluster. - */ - private static function requireMultipleMongoses(string $uri): void - { - assertStringStartsWith('mongodb://', $uri); - - $manager = FunctionalTestCase::createTestManager($uri); - - // Nothing to do if the URI does not refer to a sharded cluster - if ($manager->selectServer(new ReadPreference(ReadPreference::PRIMARY))->getType() !== Server::TYPE_MONGOS) { - return; - } - - assertStringContainsString(',', parse_url($uri, PHP_URL_HOST)); - } } diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index a49f878ef..5a2718223 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -19,23 +19,32 @@ use function call_user_func; use function count; +use function explode; use function filter_var; use function gc_collect_cycles; use function getenv; +use function implode; use function in_array; use function is_string; +use function parse_url; use function PHPUnit\Framework\assertContainsOnly; use function PHPUnit\Framework\assertInstanceOf; use function PHPUnit\Framework\assertIsArray; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertNotEmpty; +use function PHPUnit\Framework\assertNotFalse; +use function PHPUnit\Framework\assertStringContainsString; +use function PHPUnit\Framework\assertStringStartsWith; use function preg_match; use function preg_replace; use function sprintf; +use function strlen; use function strpos; +use function substr_replace; use function version_compare; use const FILTER_VALIDATE_BOOLEAN; +use const PHP_URL_HOST; /** * Unified test runner. @@ -180,8 +189,7 @@ private function doTestCase(stdClass $test, string $schemaVersion, ?array $runOn $this->prepareInitialData($initialData); } - // Give Context unmodified URI so it can enforce useMultipleMongoses - $context = new Context($this->internalClient, $this->internalClientUri); + $context = $this->createContext(); /* If an EntityMap observer has been configured, assign the Context's * EntityMap to a class property so it can later be accessed from run(), @@ -479,4 +487,71 @@ private function preventStaleDbVersionError(array $operations, Context $context) } } } + + private function createContext(): Context + { + $context = new Context($this->internalClient, $this->internalClientUri); + + if ($this->getPrimaryServer()->getType() === Server::TYPE_MONGOS) { + // We assume the internal client URI has multiple mongos hosts + $multiMongosUri = $this->internalClientUri; + + /* TODO: If an SRV URI is provided, we can consider connecting and + * checking the topology for multiple mongoses and then selecting a + * single mongos to reconstruct a single mongos URI; however, that + * may omit necessary URI options provided by TXT records. */ + assertStringStartsWith('mongodb://', $multiMongosUri); + assertStringContainsString(',', parse_url($multiMongosUri, PHP_URL_HOST)); + + $singleMongosUri = self::removeMultipleHosts($multiMongosUri); + + $context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri); + } + + /* TODO: Enable this logic once PHPLIB-794 is implemented. For now, load + * balancer tests will continue to use MONGODB_URI. */ + if (false && $this->getPrimaryServer()->getType() === Server::TYPE_LOAD_BALANCER && ! $this->isServerless()) { + $singleMongosUri = getenv('MONGODB_SINGLE_MONGOS_LB_URI'); + $multiMongosUri = getenv('MONGODB_MULTI_MONGOS_LB_URI'); + + assertNotFalse($singleMongosUri); + assertNotFalse($multiMongosUri); + + $context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri); + } + + return $context; + } + + /** + * Removes any hosts beyond the first in a URI. This function should only be + * used with a sharded cluster URI, but that is not enforced. + */ + private static function removeMultipleHosts(string $uri): string + { + $parts = parse_url($uri); + + assertIsArray($parts); + + $hosts = explode(',', $parts['host']); + + // Nothing to do if the URI already has a single mongos host + if (count($hosts) === 1) { + return $uri; + } + + // Re-append port to last host + if (isset($parts['port'])) { + $hosts[count($hosts) - 1] .= ':' . $parts['port']; + } + + $singleHost = $hosts[0]; + $multipleHosts = implode(',', $hosts); + + $pos = strpos($uri, $multipleHosts); + + assertNotFalse($pos); + + return substr_replace($uri, $singleHost, $pos, strlen($multipleHosts)); + } } diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json index c0a9b3f09..04fe8f04f 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json @@ -1,6 +1,11 @@ { "description": "change-streams-errors", "schemaVersion": "1.7", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "createEntities": [ { "client": { diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json b/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json index b6f0e2c3b..8beefb2bc 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json @@ -1,6 +1,6 @@ { "description": "change-streams-pre_and_post_images", - "schemaVersion": "1.0", + "schemaVersion": "1.4", "runOnRequirements": [ { "minServerVersion": "6.0.0", @@ -8,7 +8,8 @@ "replicaset", "sharded-replicaset", "load-balanced" - ] + ], + "serverless": "forbid" } ], "createEntities": [ diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json index 167f4bb4b..b4953ec73 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json @@ -8,7 +8,8 @@ "replicaset", "sharded-replicaset", "load-balanced" - ] + ], + "serverless": "forbid" } ], "createEntities": [ diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json index 68ea30587..c156b550c 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json @@ -8,7 +8,8 @@ "replicaset", "sharded-replicaset", "load-balanced" - ] + ], + "serverless": "forbid" } ], "createEntities": [ diff --git a/tests/UnifiedSpecTests/change-streams/change-streams.json b/tests/UnifiedSpecTests/change-streams/change-streams.json index eb8dd73af..d2fb62145 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams.json @@ -7,7 +7,8 @@ "topologies": [ "replicaset", "sharded-replicaset" - ] + ], + "serverless": "forbid" } ], "createEntities": [ diff --git a/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json b/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json index 2a2c41a68..4194005eb 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json @@ -1,6 +1,11 @@ { "description": "poc-change-streams", - "schemaVersion": "1.0", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "serverless": "forbid" + } + ], "createEntities": [ { "client": { From ec68b3cb19afffcdb9685f2daaf1d3a8159eb342 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Tue, 26 Apr 2022 23:53:04 +0300 Subject: [PATCH 139/321] PHPLIB-647: skipping CSFLE tests if mongocryptd is not available (#921) Adding check for local mongocryptd availability in CSFLE spec tests. --- .../ClientSideEncryptionSpecTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 2babb6164..587b71bc0 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -24,10 +24,12 @@ use function base64_decode; use function basename; +use function explode; use function file_get_contents; use function getenv; use function glob; use function in_array; +use function is_executable; use function iterator_to_array; use function json_decode; use function sprintf; @@ -35,6 +37,9 @@ use function strlen; use function unserialize; +use const DIRECTORY_SEPARATOR; +use const PATH_SEPARATOR; + /** * Client-side encryption spec tests. * @@ -56,6 +61,7 @@ public function setUp(): void parent::setUp(); $this->skipIfClientSideEncryptionIsNotSupported(); + $this->skipIfLocalMongocryptdIsUnavailable(); } /** @@ -1272,4 +1278,17 @@ private function prepareCorpusData(string $fieldName, stdClass $data, ClientEncr return $data->allowed ? $returnData : $data; } + + private function skipIfLocalMongocryptdIsUnavailable(): void + { + $paths = explode(PATH_SEPARATOR, getenv("PATH")); + + foreach ($paths as $path) { + if (is_executable($path . DIRECTORY_SEPARATOR . 'mongocryptd')) { + return; + } + } + + $this->markTestSkipped('Mongocryptd is not available on the localhost'); + } } From 48a280704afe811d4cd218edd80e831a093cf41c Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 6 May 2022 13:12:30 -0400 Subject: [PATCH 140/321] PHPLIB-865: valid-fail test for unsupported operation (#923) Synced with mongodb/specifications@5dbdfdbcbac15dc0b83aed104bc627c011a80adb --- .../valid-fail/operation-unsupported.json | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/UnifiedSpecTests/valid-fail/operation-unsupported.json diff --git a/tests/UnifiedSpecTests/valid-fail/operation-unsupported.json b/tests/UnifiedSpecTests/valid-fail/operation-unsupported.json new file mode 100644 index 000000000..d8ef5ab1c --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/operation-unsupported.json @@ -0,0 +1,22 @@ +{ + "description": "operation-unsupported", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0" + } + } + ], + "tests": [ + { + "description": "Unsupported operation", + "operations": [ + { + "name": "unsupportedOperation", + "object": "client0" + } + ] + } + ] +} From 580062585351360a19b57019cfca47fe46c0008c Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Wed, 11 May 2022 05:22:34 +0300 Subject: [PATCH 141/321] PHPLIB-838: Add CSFLE spec test for auto encryption on a collection with no jsonSchema (#922) Synced with mongodb/specifications@02b4275d4e53dcadf87682b9e07f08a86a7b81d5 --- .../tests/noSchema.json | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/SpecTests/client-side-encryption/tests/noSchema.json diff --git a/tests/SpecTests/client-side-encryption/tests/noSchema.json b/tests/SpecTests/client-side-encryption/tests/noSchema.json new file mode 100644 index 000000000..095434f88 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/noSchema.json @@ -0,0 +1,67 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "unencrypted", + "tests": [ + { + "description": "Insert on an unencrypted collection", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1 + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "unencrypted" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "insert": "unencrypted", + "documents": [ + { + "_id": 1 + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1 + } + ] + } + } + } + ] +} From c14ac1f0b74ab98085a2f2ac66ca883daf2099c0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 16 May 2022 14:24:09 -0400 Subject: [PATCH 142/321] PHPLIB-843: Support clusteredIndex option for createCollection Fixes preparation of database, collection, and index enumeration results. The new spec tests are the first to assert these results (including those for legacy test runners). Sync collection-management spec tests with mongodb/specifications@d1458823bd810014df9da16d3a5354d2269ab865, which also covers PHPLIB-856 --- ...tabase-method-createCollection-option.yaml | 17 ++ src/Operation/CreateCollection.php | 10 +- tests/Operation/CreateCollectionTest.php | 4 + tests/UnifiedSpecTests/Operation.php | 24 ++- tests/UnifiedSpecTests/Util.php | 2 +- .../clustered-indexes.json | 177 ++++++++++++++++++ .../createCollection-pre_and_post_images.json | 92 +++++++++ .../modifyCollection-pre_and_post_images.json | 111 +++++++++++ 8 files changed, 432 insertions(+), 5 deletions(-) create mode 100644 tests/UnifiedSpecTests/collection-management/clustered-indexes.json create mode 100644 tests/UnifiedSpecTests/collection-management/createCollection-pre_and_post_images.json create mode 100644 tests/UnifiedSpecTests/collection-management/modifyCollection-pre_and_post_images.json diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 4c341d91e..549c053f3 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -27,6 +27,23 @@ interface: phpmethod operation: ~ optional: true --- +arg_name: option +name: clusteredIndex +type: document +description: | + A clustered index specification. See + :manual:`Clustered Collections ` or the + :manual:`create ` command documentation for more + information. + + This option is available in MongoDB 5.3+ and will result in an exception at + execution time if specified for an older server version. + + .. versionadded:: 1.13 +interface: phpmethod +operation: ~ +optional: true +--- source: file: apiargs-common-option.yaml ref: collation diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index de771399b..edb3be154 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -71,6 +71,10 @@ class CreateCollection implements Executable * * capped (boolean): Specify true to create a capped collection. If set, * the size option must also be specified. The default is false. * + * * clusteredIndex (document): A clustered index specification. + * + * This is not supported for server versions < 5.3. + * * * collation (document): Collation specification. * * * expireAfterSeconds: The TTL for documents in time series collections. @@ -129,6 +133,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"capped" option', $options['capped'], 'boolean'); } + if (isset($options['clusteredIndex']) && ! is_array($options['clusteredIndex']) && ! is_object($options['clusteredIndex'])) { + throw InvalidArgumentException::invalidType('"clusteredIndex" option', $options['clusteredIndex'], 'array or object'); + } + if (isset($options['collation']) && ! is_array($options['collation']) && ! is_object($options['collation'])) { throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); } @@ -236,7 +244,7 @@ private function createCommand() } } - foreach (['collation', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { + foreach (['clusteredIndex', 'collation', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = (object) $this->options[$option]; } diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index 02d1987d6..1a7fdf950 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -28,6 +28,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['capped' => $value]; } + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['clusteredIndex' => $value]; + } + foreach ($this->getInvalidDocumentValues() as $value) { $options[][] = ['collation' => $value]; } diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index b68a16a64..f3959c3b0 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -12,6 +12,8 @@ use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\GridFS\Bucket; +use MongoDB\Model\CollectionInfo; +use MongoDB\Model\DatabaseInfo; use MongoDB\Model\IndexInfo; use MongoDB\Operation\DatabaseCommand; use MongoDB\Operation\FindOneAndReplace; @@ -23,6 +25,7 @@ use Throwable; use function array_diff_key; +use function array_intersect_key; use function array_key_exists; use function array_map; use function current; @@ -260,7 +263,12 @@ private function executeForClient(Client $client) return iterator_to_array($client->listDatabaseNames($args)); case 'listDatabases': - return iterator_to_array($client->listDatabases($args)); + return array_map( + function (DatabaseInfo $info) { + return $info->__debugInfo(); + }, + iterator_to_array($client->listDatabases($args)) + ); default: Assert::fail('Unsupported client operation: ' . $this->name); @@ -457,7 +465,12 @@ private function executeForCollection(Collection $collection) ); case 'listIndexes': - return iterator_to_array($collection->listIndexes($args)); + return array_map( + function (IndexInfo $info) { + return $info->__debugInfo(); + }, + iterator_to_array($collection->listIndexes($args)) + ); case 'mapReduce': assertArrayHasKey('map', $args); @@ -579,7 +592,12 @@ private function executeForDatabase(Database $database) return iterator_to_array($database->listCollectionNames($args)); case 'listCollections': - return iterator_to_array($database->listCollections($args)); + return array_map( + function (CollectionInfo $info) { + return $info->__debugInfo(); + }, + iterator_to_array($database->listCollections($args)) + ); case 'runCommand': assertArrayHasKey('command', $args); diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index c7fc7f559..f9aa568be 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -62,7 +62,7 @@ final class Util Database::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], - 'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator'], + 'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator'], 'dropCollection' => ['collection', 'session'], 'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], 'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], diff --git a/tests/UnifiedSpecTests/collection-management/clustered-indexes.json b/tests/UnifiedSpecTests/collection-management/clustered-indexes.json new file mode 100644 index 000000000..739d0fd8b --- /dev/null +++ b/tests/UnifiedSpecTests/collection-management/clustered-indexes.json @@ -0,0 +1,177 @@ +{ + "description": "clustered-indexes", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "5.3", + "serverless": "forbid" + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "ts-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "ts-tests", + "documents": [] + } + ], + "tests": [ + { + "description": "createCollection with clusteredIndex", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index" + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "databaseName": "ts-tests", + "collectionName": "test" + } + } + ] + }, + { + "description": "listCollections includes clusteredIndex", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index" + } + } + }, + { + "name": "listCollections", + "object": "database0", + "arguments": { + "filter": { + "name": { + "$eq": "test" + } + } + }, + "expectResult": [ + { + "name": "test", + "options": { + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index", + "v": { + "$$type": [ + "int", + "long" + ] + } + } + } + } + ] + } + ] + }, + { + "description": "listIndexes returns the index", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index" + } + } + }, + { + "name": "listIndexes", + "object": "collection0", + "expectResult": [ + { + "key": { + "_id": 1 + }, + "name": "test index", + "clustered": true, + "unique": true, + "v": { + "$$type": [ + "int", + "long" + ] + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/collection-management/createCollection-pre_and_post_images.json b/tests/UnifiedSpecTests/collection-management/createCollection-pre_and_post_images.json new file mode 100644 index 000000000..f488deacd --- /dev/null +++ b/tests/UnifiedSpecTests/collection-management/createCollection-pre_and_post_images.json @@ -0,0 +1,92 @@ +{ + "description": "createCollection-pre_and_post_images", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "6.0", + "serverless": "forbid" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "papi-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "tests": [ + { + "description": "createCollection with changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "databaseName": "papi-tests", + "collectionName": "test" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "papi-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + }, + "databaseName": "papi-tests" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/collection-management/modifyCollection-pre_and_post_images.json b/tests/UnifiedSpecTests/collection-management/modifyCollection-pre_and_post_images.json new file mode 100644 index 000000000..8026faeb1 --- /dev/null +++ b/tests/UnifiedSpecTests/collection-management/modifyCollection-pre_and_post_images.json @@ -0,0 +1,111 @@ +{ + "description": "modifyCollection-pre_and_post_images", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "6.0", + "serverless": "forbid" + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "papi-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "tests": [ + { + "description": "modifyCollection to changeStreamPreAndPostImages enabled", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "test" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "databaseName": "papi-tests", + "collectionName": "test" + } + }, + { + "name": "modifyCollection", + "object": "database0", + "arguments": { + "collection": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "papi-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "changeStreamPreAndPostImages": { + "enabled": false + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "collMod": "test", + "changeStreamPreAndPostImages": { + "enabled": true + } + } + } + } + ] + } + ] + } + ] +} From bdb701e0c9888ee12b684f38a59351415484502d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 16 May 2022 15:08:22 -0400 Subject: [PATCH 143/321] PHPLIB-856: changeStreamPreAndPostImages create and collMod option This should originally have been added in 2704fb05e3a96cc63544c2f6e0c33008740b6915 for PHPLIB-814. --- ...BDatabase-method-createCollection-option.yaml | 16 ++++++++++++++++ src/Operation/CreateCollection.php | 11 ++++++++++- tests/Operation/CreateCollectionTest.php | 4 ++++ tests/UnifiedSpecTests/Operation.php | 16 ++++++++++++++++ tests/UnifiedSpecTests/Util.php | 1 + 5 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 549c053f3..9b0ae8a6a 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -28,6 +28,22 @@ operation: ~ optional: true --- arg_name: option +name: changeStreamPreAndPostImages +type: document +description: | + Used to configure support for pre- and post-images in change streams. See the + :manual:`create ` command documentation for more + information. + + This option is available in MongoDB 6.0+ and will result in an exception at + execution time if specified for an older server version. + + .. versionadded:: 1.13 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: clusteredIndex type: document description: | diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index edb3be154..e3819d819 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -71,6 +71,11 @@ class CreateCollection implements Executable * * capped (boolean): Specify true to create a capped collection. If set, * the size option must also be specified. The default is false. * + * * changeStreamPreAndPostImages (document): Used to configure support for + * pre- and post-images in change streams. + * + * This is not supported for server versions < 6.0. + * * * clusteredIndex (document): A clustered index specification. * * This is not supported for server versions < 5.3. @@ -133,6 +138,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"capped" option', $options['capped'], 'boolean'); } + if (isset($options['changeStreamPreAndPostImages']) && ! is_array($options['changeStreamPreAndPostImages']) && ! is_object($options['changeStreamPreAndPostImages'])) { + throw InvalidArgumentException::invalidType('"changeStreamPreAndPostImages" option', $options['changeStreamPreAndPostImages'], 'array or object'); + } + if (isset($options['clusteredIndex']) && ! is_array($options['clusteredIndex']) && ! is_object($options['clusteredIndex'])) { throw InvalidArgumentException::invalidType('"clusteredIndex" option', $options['clusteredIndex'], 'array or object'); } @@ -244,7 +253,7 @@ private function createCommand() } } - foreach (['clusteredIndex', 'collation', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { + foreach (['changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = (object) $this->options[$option]; } diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index 1a7fdf950..efc6806c3 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -28,6 +28,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['capped' => $value]; } + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['changeStreamPreAndPostImages' => $value]; + } + foreach ($this->getInvalidDocumentValues() as $value) { $options[][] = ['clusteredIndex' => $value]; } diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index f3959c3b0..40f746083 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -599,6 +599,22 @@ function (CollectionInfo $info) { iterator_to_array($database->listCollections($args)) ); + case 'modifyCollection': + assertArrayHasKey('collection', $args); + assertIsString($args['collection']); + + /* ModifyCollection takes collection and command options + * separately, so we must split the array after initially + * filtering out the collection name. + * + * The typeMap option is intentionally omitted since it is + * specific to PHPLIB and will never appear in spec tests. */ + $options = array_diff_key($args, ['collection' => 1]); + $collectionOptions = array_diff_key($options, ['session' => 1, 'writeConcern' => 1]); + $options = array_intersect_key($options, ['session' => 1, 'writeConcern' => 1]); + + return $database->modifyCollection($args['collection'], $collectionOptions, $options); + case 'runCommand': assertArrayHasKey('command', $args); assertInstanceOf(stdClass::class, $args['command']); diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index f9aa568be..98c617dcc 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -66,6 +66,7 @@ final class Util 'dropCollection' => ['collection', 'session'], 'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], 'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], + 'modifyCollection' => ['collection', 'changeStreamPreAndPostImages'], // Note: commandName is not used by PHP 'runCommand' => ['command', 'session', 'commandName'], ], From 4958788d6c13f06ddef15053ecf8fd28054dbcb9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 16 May 2022 16:48:47 -0400 Subject: [PATCH 144/321] PHPLIB-874: commandStartedEvent assertions for clusteredIndex tests Synced with mongodb/specifications@600b1af878dc79353b856d026b0ad879577122d3 --- .../clustered-indexes.json | 122 +++++++++++++++++- 1 file changed, 118 insertions(+), 4 deletions(-) diff --git a/tests/UnifiedSpecTests/collection-management/clustered-indexes.json b/tests/UnifiedSpecTests/collection-management/clustered-indexes.json index 739d0fd8b..9db5ff06d 100644 --- a/tests/UnifiedSpecTests/collection-management/clustered-indexes.json +++ b/tests/UnifiedSpecTests/collection-management/clustered-indexes.json @@ -10,14 +10,17 @@ "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] } }, { "database": { "id": "database0", "client": "client0", - "databaseName": "ts-tests" + "databaseName": "ci-tests" } }, { @@ -31,7 +34,7 @@ "initialData": [ { "collectionName": "test", - "databaseName": "ts-tests", + "databaseName": "ci-tests", "documents": [] } ], @@ -64,10 +67,40 @@ "name": "assertCollectionExists", "object": "testRunner", "arguments": { - "databaseName": "ts-tests", + "databaseName": "ci-tests", "collectionName": "test" } } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "ci-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index" + } + }, + "databaseName": "ci-tests" + } + } + ] + } ] }, { @@ -125,6 +158,49 @@ } ] } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "ci-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index" + } + }, + "databaseName": "ci-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "listCollections": 1, + "filter": { + "name": { + "$eq": "test" + } + } + }, + "databaseName": "ci-tests" + } + } + ] + } ] }, { @@ -171,6 +247,44 @@ } ] } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "drop": "test" + }, + "databaseName": "ci-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "test", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true, + "name": "test index" + } + }, + "databaseName": "ci-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "listIndexes": "test" + }, + "databaseName": "ci-tests" + } + } + ] + } ] } ] From af516ebe1d216d859ba9f60fdb0a6755b2516a83 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 18 May 2022 13:20:15 -0400 Subject: [PATCH 145/321] PHPLIB-873: Restrict unified change stream tests to replica sets (#931) This is a temporary solution to address flaky test failures on sharded clusters. Synced with mongodb/specifications@f07351c0c61cd79e0e7a197f78a5cfcc028c2966 --- .../change-streams/change-streams.json | 72 ++++++------------- 1 file changed, 22 insertions(+), 50 deletions(-) diff --git a/tests/UnifiedSpecTests/change-streams/change-streams.json b/tests/UnifiedSpecTests/change-streams/change-streams.json index d2fb62145..99f5624ac 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams.json @@ -5,8 +5,7 @@ { "minServerVersion": "3.6", "topologies": [ - "replicaset", - "sharded-replicaset" + "replicaset" ], "serverless": "forbid" } @@ -314,10 +313,7 @@ "description": "Test that comment is set on getMore", "runOnRequirements": [ { - "minServerVersion": "4.4.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "4.4.0" } ], "operations": [ @@ -405,10 +401,7 @@ "description": "Test that comment is not set on getMore - pre 4.4", "runOnRequirements": [ { - "maxServerVersion": "4.3.99", - "topologies": [ - "replicaset" - ] + "maxServerVersion": "4.3.99" } ], "operations": [ @@ -621,6 +614,15 @@ }, { "description": "Test new structure in ns document MUST NOT err", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "maxServerVersion": "5.2.99" + }, + { + "minServerVersion": "6.0" + } + ], "operations": [ { "name": "createChangeStream", @@ -797,10 +799,7 @@ "description": "$changeStream must be the first stage in a change stream pipeline sent to the server", "runOnRequirements": [ { - "minServerVersion": "3.6.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.6.0" } ], "operations": [ @@ -873,10 +872,7 @@ "description": "The server returns change stream responses in the specified server response format", "runOnRequirements": [ { - "minServerVersion": "3.6.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.6.0" } ], "operations": [ @@ -926,10 +922,7 @@ "description": "Executing a watch helper on a Collection results in notifications for changes to the specified collection", "runOnRequirements": [ { - "minServerVersion": "3.6.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.6.0" } ], "operations": [ @@ -1014,10 +1007,7 @@ "description": "Change Stream should allow valid aggregate pipeline stages", "runOnRequirements": [ { - "minServerVersion": "3.6.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.6.0" } ], "operations": [ @@ -1104,10 +1094,7 @@ "description": "Executing a watch helper on a Database results in notifications for changes to all collections in the specified database.", "runOnRequirements": [ { - "minServerVersion": "3.8.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.8.0" } ], "operations": [ @@ -1209,10 +1196,7 @@ "description": "Executing a watch helper on a MongoClient results in notifications for changes to all collections in all databases in the cluster.", "runOnRequirements": [ { - "minServerVersion": "3.8.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.8.0" } ], "operations": [ @@ -1333,10 +1317,7 @@ "description": "Test insert, update, replace, and delete event types", "runOnRequirements": [ { - "minServerVersion": "3.6.0", - "topologies": [ - "replicaset" - ] + "minServerVersion": "3.6.0" } ], "operations": [ @@ -1488,10 +1469,7 @@ "description": "Test rename and invalidate event types", "runOnRequirements": [ { - "minServerVersion": "4.0.1", - "topologies": [ - "replicaset" - ] + "minServerVersion": "4.0.1" } ], "operations": [ @@ -1568,10 +1546,7 @@ "description": "Test drop and invalidate event types", "runOnRequirements": [ { - "minServerVersion": "4.0.1", - "topologies": [ - "replicaset" - ] + "minServerVersion": "4.0.1" } ], "operations": [ @@ -1637,10 +1612,7 @@ "description": "Test consecutive resume", "runOnRequirements": [ { - "minServerVersion": "4.1.7", - "topologies": [ - "replicaset" - ] + "minServerVersion": "4.1.7" } ], "operations": [ From 67eebe52b481ac2e6255a1f6de3ef9b691cd6256 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Wed, 18 May 2022 20:22:55 +0300 Subject: [PATCH 146/321] PHPLIB-718: APM spec tests for serverConnectionId (#930) Relevant spec tests were previously updated in c4302b943cae7537a16e2f2668f33abc9fa28b72 for PHPLIB-671. --- tests/UnifiedSpecTests/EventObserver.php | 21 +++++++++++++++++--- tests/UnifiedSpecTests/UnifiedSpecTest.php | 3 --- tests/UnifiedSpecTests/UnifiedTestRunner.php | 1 - 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php index 651d21b2d..842dfb89a 100644 --- a/tests/UnifiedSpecTests/EventObserver.php +++ b/tests/UnifiedSpecTests/EventObserver.php @@ -262,7 +262,7 @@ private function assertEvent($actual, stdClass $expected, string $message) private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass $expected, string $message): void { - Util::assertHasOnlyKeys($expected, ['command', 'commandName', 'databaseName', 'hasServiceId']); + Util::assertHasOnlyKeys($expected, ['command', 'commandName', 'databaseName', 'hasServiceId', 'hasServerConnectionId']); if (isset($expected->command)) { assertIsObject($expected->command); @@ -284,11 +284,16 @@ private function assertCommandStartedEvent(CommandStartedEvent $actual, stdClass assertIsBool($expected->hasServiceId); assertSame($actual->getServiceId() !== null, $expected->hasServiceId, $message . ': hasServiceId matches'); } + + if (isset($expected->hasServerConnectionId)) { + assertIsBool($expected->hasServerConnectionId); + assertSame($actual->getServerConnectionId() !== null, $expected->hasServerConnectionId, $message . ': hasServerConnectionId matches'); + } } private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdClass $expected, string $message): void { - Util::assertHasOnlyKeys($expected, ['reply', 'commandName', 'hasServiceId']); + Util::assertHasOnlyKeys($expected, ['reply', 'commandName', 'hasServiceId', 'hasServerConnectionId']); if (isset($expected->reply)) { assertIsObject($expected->reply); @@ -305,11 +310,16 @@ private function assertCommandSucceededEvent(CommandSucceededEvent $actual, stdC assertIsBool($expected->hasServiceId); assertSame($actual->getServiceId() !== null, $expected->hasServiceId, $message . ': hasServiceId matches'); } + + if (isset($expected->hasServerConnectionId)) { + assertIsBool($expected->hasServerConnectionId); + assertSame($actual->getServerConnectionId() !== null, $expected->hasServerConnectionId, $message . ': hasServerConnectionId matches'); + } } private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $expected, string $message): void { - Util::assertHasOnlyKeys($expected, ['commandName', 'hasServiceId']); + Util::assertHasOnlyKeys($expected, ['commandName', 'hasServiceId', 'hasServerConnectionId']); if (isset($expected->commandName)) { assertIsString($expected->commandName); @@ -320,6 +330,11 @@ private function assertCommandFailedEvent(CommandFailedEvent $actual, stdClass $ assertIsBool($expected->hasServiceId); assertSame($actual->getServiceId() !== null, $expected->hasServiceId, $message . ': hasServiceId matches'); } + + if (isset($expected->hasServerConnectionId)) { + assertIsBool($expected->hasServerConnectionId); + assertSame($actual->getServerConnectionId() !== null, $expected->hasServerConnectionId, $message . ': hasServerConnectionId matches'); + } } /** @param CommandStartedEvent|CommandSucceededEvent|CommandFailedEvent $event */ diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 5db237cbb..80b531255 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -59,9 +59,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType can be set to command and cmap' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType defaults to command if unset' => 'PHPC does not implement CMAP', - // Command monitoring event serverConnectionId is not yet implemented - 'command-monitoring/pre-42-server-connection-id: command events do not include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', - 'command-monitoring/server-connection-id: command events include server connection id' => 'Not yet implemented (PHPC-1899, PHPLIB-718)', // Change stream "comment" option is not yet implemented 'change-streams/change-streams: Test with document comment' => 'Not yet implemented (PHPLIB-749)', 'change-streams/change-streams: Test with document comment - pre 4.4' => 'Not yet implemented (PHPLIB-749)', diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 5a2718223..a378f7996 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -60,7 +60,6 @@ final class UnifiedTestRunner public const MIN_SCHEMA_VERSION = '1.0'; - // Note: schema version 1.6 is not yet implemented (see: PHPLIB-718) public const MAX_SCHEMA_VERSION = '1.7'; /** @var MongoDB\Client */ From d620cc0bdbce3e82a697f485495f70614acd106b Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Thu, 19 May 2022 19:51:57 +0300 Subject: [PATCH 147/321] PHPLIB-810: Always use count command for estimatedDocumentCount (#926) Spec tests synced with mongodb/specifications@021cbc80e1e444023fd05d8092df4546e639db40 Co-authored-by: Jeremy Mikola --- src/Operation/EstimatedDocumentCount.php | 45 +- .../estimatedDocumentCount.json | 19 +- .../estimatedDocumentCount-4.9.json | 246 ----- ...timatedDocumentCount-serverErrors-4.9.json | 911 ------------------ ... estimatedDocumentCount-serverErrors.json} | 2 - ...re4.9.json => estimatedDocumentCount.json} | 2 - tests/UnifiedSpecTests/UnifiedSpecTest.php | 7 + .../crud/bulkWrite-comment.json | 1 + .../crud/countDocuments-comment.json | 208 ++++ .../crud/deleteMany-comment.json | 1 + .../crud/deleteOne-comment.json | 1 + .../crud/estimatedDocumentCount-comment.json | 170 ++++ .../crud/estimatedDocumentCount.json | 371 ++----- .../crud/insertMany-comment.json | 1 + .../crud/insertOne-comment.json | 1 + .../crud/replaceOne-comment.json | 1 + .../crud/updateMany-comment.json | 1 + .../crud/updateOne-comment.json | 1 + .../crud-api-version-1-strict.json | 26 +- .../versioned-api/crud-api-version-1.json | 28 +- 20 files changed, 501 insertions(+), 1542 deletions(-) delete mode 100644 tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json delete mode 100644 tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json rename tests/SpecTests/retryable-reads/{estimatedDocumentCount-serverErrors-pre4.9.json => estimatedDocumentCount-serverErrors.json} (99%) rename tests/SpecTests/retryable-reads/{estimatedDocumentCount-pre4.9.json => estimatedDocumentCount.json} (97%) create mode 100644 tests/UnifiedSpecTests/crud/countDocuments-comment.json create mode 100644 tests/UnifiedSpecTests/crud/estimatedDocumentCount-comment.json diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index 53f810f64..e4e731eec 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -17,7 +17,6 @@ namespace MongoDB\Operation; -use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; @@ -29,7 +28,6 @@ use function array_intersect_key; use function is_integer; -use function MongoDB\server_supports_feature; /** * Operation for obtaining an estimated count of documents in a collection @@ -111,25 +109,7 @@ public function __construct($databaseName, $collectionName, array $options = []) */ public function execute(Server $server) { - $command = $this->createCommand($server); - - if ($command instanceof Aggregate) { - try { - $cursor = $command->execute($server); - } catch (CommandException $e) { - if ($e->getCode() == self::$errorCodeCollectionNotFound) { - return 0; - } - - throw $e; - } - - $cursor->rewind(); - - return $cursor->current()->n; - } - - return $command->execute($server); + return $this->createCount()->execute($server); } /** @@ -141,28 +121,7 @@ public function execute(Server $server) */ public function getCommandDocument(Server $server) { - return $this->createCommand($server)->getCommandDocument($server); - } - - private function createAggregate(): Aggregate - { - return new Aggregate( - $this->databaseName, - $this->collectionName, - [ - ['$collStats' => ['count' => (object) []]], - ['$group' => ['_id' => 1, 'n' => ['$sum' => '$count']]], - ], - $this->options - ); - } - - /** @return Aggregate|Count */ - private function createCommand(Server $server) - { - return server_supports_feature($server, self::$wireVersionForCollStats) - ? $this->createAggregate() - : $this->createCount(); + return $this->createCount()->getCommandDocument($server); } private function createCount(): Count diff --git a/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json b/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json index 87b385208..997a3ab3f 100644 --- a/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json +++ b/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json @@ -15,24 +15,9 @@ { "command_started_event": { "command": { - "aggregate": "driverdata", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] + "count": "driverdata" }, - "command_name": "aggregate", + "command_name": "count", "database_name": "test" } } diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json deleted file mode 100644 index a4c46fc07..000000000 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-4.9.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.9.0" - } - ], - "database_name": "retryable-reads-tests", - "collection_name": "coll", - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "tests": [ - { - "description": "EstimatedDocumentCount succeeds on first attempt", - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds on second attempt", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount fails on first attempt", - "clientOptions": { - "retryReads": false - }, - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount fails on second attempt", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 2 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "closeConnection": true - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json deleted file mode 100644 index 756b02b3a..000000000 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-4.9.json +++ /dev/null @@ -1,911 +0,0 @@ -{ - "runOn": [ - { - "minServerVersion": "4.9.0" - } - ], - "database_name": "retryable-reads-tests", - "collection_name": "coll", - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - } - ], - "tests": [ - { - "description": "EstimatedDocumentCount succeeds after InterruptedAtShutdown", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 11600 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after InterruptedDueToReplStateChange", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 11602 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after NotWritablePrimary", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 10107 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after NotPrimaryNoSecondaryOk", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 13435 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after NotPrimaryOrSecondary", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 13436 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after PrimarySteppedDown", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 189 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after ShutdownInProgress", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 91 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after HostNotFound", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 7 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after HostUnreachable", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 6 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after NetworkTimeout", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 89 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount succeeds after SocketException", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 9001 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "result": 2 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount fails after two NotWritablePrimary errors", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 2 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 10107 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - }, - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - }, - { - "description": "EstimatedDocumentCount fails after NotWritablePrimary when retryReads is false", - "clientOptions": { - "retryReads": false - }, - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 10107 - } - }, - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection", - "error": true - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "coll", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "database_name": "retryable-reads-tests" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors.json similarity index 99% rename from tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json rename to tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors.json index 0b9a2615d..6bb128f5f 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors-pre4.9.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount-serverErrors.json @@ -2,7 +2,6 @@ "runOn": [ { "minServerVersion": "4.0", - "maxServerVersion": "4.8.99", "topology": [ "single", "replicaset" @@ -10,7 +9,6 @@ }, { "minServerVersion": "4.1.7", - "maxServerVersion": "4.8.99", "topology": [ "sharded" ] diff --git a/tests/SpecTests/retryable-reads/estimatedDocumentCount-pre4.9.json b/tests/SpecTests/retryable-reads/estimatedDocumentCount.json similarity index 97% rename from tests/SpecTests/retryable-reads/estimatedDocumentCount-pre4.9.json rename to tests/SpecTests/retryable-reads/estimatedDocumentCount.json index 44be966ae..8dfa15a2c 100644 --- a/tests/SpecTests/retryable-reads/estimatedDocumentCount-pre4.9.json +++ b/tests/SpecTests/retryable-reads/estimatedDocumentCount.json @@ -2,7 +2,6 @@ "runOn": [ { "minServerVersion": "4.0", - "maxServerVersion": "4.8.99", "topology": [ "single", "replicaset" @@ -10,7 +9,6 @@ }, { "minServerVersion": "4.1.7", - "maxServerVersion": "4.8.99", "topology": [ "sharded" ] diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 80b531255..1b735d6da 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -69,6 +69,11 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/bulkWrite-comment: BulkWrite with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/bulkWrite-comment: BulkWrite with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/bulkWrite-comment: BulkWrite with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/countDocuments-comment: countDocuments with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/countDocuments-comment: countDocuments with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/estimatedDocumentCount-comment: estimatedDocumentCount with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/estimatedDocumentCount-comment: estimatedDocumentCount with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + 'crud/estimatedDocumentCount-comment: estimatedDocumentCount with document comment - pre 4.4.14, server error' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/deleteMany-comment: deleteMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/deleteMany-comment: deleteMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/deleteMany-comment: deleteMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', @@ -106,6 +111,8 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', + // CreateCollection "viewOn" and "pipeline" options are not yet implemented + 'crud/estimatedDocumentCount: estimatedDocumentCount works correctly on views' => 'Not yet implemented (PHPLIB-869)', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-comment.json b/tests/UnifiedSpecTests/crud/bulkWrite-comment.json index de044fca9..0b2addc85 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-comment.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-comment.json @@ -412,6 +412,7 @@ "description": "BulkWrite with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/countDocuments-comment.json b/tests/UnifiedSpecTests/crud/countDocuments-comment.json new file mode 100644 index 000000000..e6c7ae817 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/countDocuments-comment.json @@ -0,0 +1,208 @@ +{ + "description": "countDocuments-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "countDocuments-comments-test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "countDocuments-comments-test", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "countDocuments with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "name": "countDocuments", + "object": "collection0", + "arguments": { + "filter": {}, + "comment": { + "key": "value" + } + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": {} + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "comment": { + "key": "value" + } + }, + "commandName": "aggregate", + "databaseName": "countDocuments-comments-test" + } + } + ] + } + ] + }, + { + "description": "countDocuments with string comment", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0" + } + ], + "operations": [ + { + "name": "countDocuments", + "object": "collection0", + "arguments": { + "filter": {}, + "comment": "comment" + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": {} + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "comment": "comment" + }, + "commandName": "aggregate", + "databaseName": "countDocuments-comments-test" + } + } + ] + } + ] + }, + { + "description": "countDocuments with document comment on less than 4.4.0 - server error", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.3.99" + } + ], + "operations": [ + { + "name": "countDocuments", + "object": "collection0", + "arguments": { + "filter": {}, + "comment": { + "key": "value" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "coll0", + "pipeline": [ + { + "$match": {} + }, + { + "$group": { + "_id": 1, + "n": { + "$sum": 1 + } + } + } + ], + "comment": { + "key": "value" + } + }, + "commandName": "aggregate", + "databaseName": "countDocuments-comments-test" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteMany-comment.json b/tests/UnifiedSpecTests/crud/deleteMany-comment.json index ea6a8524d..6abc5fd58 100644 --- a/tests/UnifiedSpecTests/crud/deleteMany-comment.json +++ b/tests/UnifiedSpecTests/crud/deleteMany-comment.json @@ -175,6 +175,7 @@ "description": "deleteMany with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/deleteOne-comment.json b/tests/UnifiedSpecTests/crud/deleteOne-comment.json index 37f356ec6..0f42b086a 100644 --- a/tests/UnifiedSpecTests/crud/deleteOne-comment.json +++ b/tests/UnifiedSpecTests/crud/deleteOne-comment.json @@ -177,6 +177,7 @@ "description": "deleteOne with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/estimatedDocumentCount-comment.json b/tests/UnifiedSpecTests/crud/estimatedDocumentCount-comment.json new file mode 100644 index 000000000..6c0adacc8 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/estimatedDocumentCount-comment.json @@ -0,0 +1,170 @@ +{ + "description": "estimatedDocumentCount-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "edc-comment-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "edc-comment-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "estimatedDocumentCount with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4.14" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "comment": { + "key": "value" + } + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0", + "comment": { + "key": "value" + } + }, + "commandName": "count", + "databaseName": "edc-comment-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "comment": "comment" + }, + "expectResult": 3 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0", + "comment": "comment" + }, + "commandName": "count", + "databaseName": "edc-comment-tests" + } + } + ] + } + ] + }, + { + "description": "estimatedDocumentCount with document comment - pre 4.4.14, server error", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.13", + "topologies": [ + "single", + "replicaset" + ] + } + ], + "operations": [ + { + "name": "estimatedDocumentCount", + "object": "collection0", + "arguments": { + "comment": { + "key": "value" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "coll0", + "comment": { + "key": "value" + } + }, + "commandName": "count", + "databaseName": "edc-comment-tests" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json b/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json index bcd66ea95..1b650c1cb 100644 --- a/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json +++ b/tests/UnifiedSpecTests/crud/estimatedDocumentCount.json @@ -34,6 +34,13 @@ "database": "database0", "collectionName": "coll1" } + }, + { + "collection": { + "id": "collection0View", + "database": "database0", + "collectionName": "coll0view" + } } ], "initialData": [ @@ -58,12 +65,7 @@ ], "tests": [ { - "description": "estimatedDocumentCount uses $collStats on 4.9.0 or greater", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], + "description": "estimatedDocumentCount always uses count", "operations": [ { "name": "estimatedDocumentCount", @@ -78,24 +80,9 @@ { "commandStartedEvent": { "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] + "count": "coll0" }, - "commandName": "aggregate", + "commandName": "count", "databaseName": "edc-tests" } } @@ -104,12 +91,7 @@ ] }, { - "description": "estimatedDocumentCount with maxTimeMS on 4.9.0 or greater", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], + "description": "estimatedDocumentCount with maxTimeMS", "operations": [ { "name": "estimatedDocumentCount", @@ -127,25 +109,10 @@ { "commandStartedEvent": { "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ], + "count": "coll0", "maxTimeMS": 6000 }, - "commandName": "aggregate", + "commandName": "count", "databaseName": "edc-tests" } } @@ -154,12 +121,7 @@ ] }, { - "description": "estimatedDocumentCount on non-existent collection on 4.9.0 or greater", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } - ], + "description": "estimatedDocumentCount on non-existent collection", "operations": [ { "name": "estimatedDocumentCount", @@ -174,24 +136,9 @@ { "commandStartedEvent": { "command": { - "aggregate": "coll1", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] + "count": "coll1" }, - "commandName": "aggregate", + "commandName": "count", "databaseName": "edc-tests" } } @@ -200,78 +147,21 @@ ] }, { - "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--command error", + "description": "estimatedDocumentCount errors correctly--command error", "runOnRequirements": [ { - "minServerVersion": "4.9.0" - } - ], - "operations": [ - { - "name": "failPoint", - "object": "testRunner", - "arguments": { - "client": "client0", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "aggregate" - ], - "errorCode": 8 - } - } - } + "minServerVersion": "4.0.0", + "topologies": [ + "single", + "replicaset" + ] }, { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectError": { - "errorCode": 8 - } - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } - } + "minServerVersion": "4.2.0", + "topologies": [ + "sharded" ] } - ] - }, - { - "description": "estimatedDocumentCount errors correctly on 4.9.0 or greater--socket error", - "runOnRequirements": [ - { - "minServerVersion": "4.9.0" - } ], "operations": [ { @@ -286,9 +176,9 @@ }, "data": { "failCommands": [ - "aggregate" + "count" ], - "closeConnection": true + "errorCode": 8 } } } @@ -297,56 +187,10 @@ "name": "estimatedDocumentCount", "object": "collection0", "expectError": { - "isError": true + "errorCode": 8 } } ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "aggregate": "coll0", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ] - }, - "commandName": "aggregate", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, - { - "description": "estimatedDocumentCount uses count on less than 4.9.0", - "runOnRequirements": [ - { - "maxServerVersion": "4.8.99" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection0", - "expectResult": 3 - } - ], "expectEvents": [ { "client": "client0", @@ -365,77 +209,10 @@ ] }, { - "description": "estimatedDocumentCount with maxTimeMS on less than 4.9.0", - "runOnRequirements": [ - { - "maxServerVersion": "4.8.99" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection0", - "arguments": { - "maxTimeMS": 6000 - }, - "expectResult": 3 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll0", - "maxTimeMS": 6000 - }, - "commandName": "count", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, - { - "description": "estimatedDocumentCount on non-existent collection on less than 4.9.0", - "runOnRequirements": [ - { - "maxServerVersion": "4.8.99" - } - ], - "operations": [ - { - "name": "estimatedDocumentCount", - "object": "collection1", - "expectResult": 0 - } - ], - "expectEvents": [ - { - "client": "client0", - "events": [ - { - "commandStartedEvent": { - "command": { - "count": "coll1" - }, - "commandName": "count", - "databaseName": "edc-tests" - } - } - ] - } - ] - }, - { - "description": "estimatedDocumentCount errors correctly on less than 4.9.0--command error", + "description": "estimatedDocumentCount errors correctly--socket error", "runOnRequirements": [ { "minServerVersion": "4.0.0", - "maxServerVersion": "4.8.99", "topologies": [ "single", "replicaset" @@ -443,7 +220,6 @@ }, { "minServerVersion": "4.2.0", - "maxServerVersion": "4.8.99", "topologies": [ "sharded" ] @@ -464,7 +240,7 @@ "failCommands": [ "count" ], - "errorCode": 8 + "closeConnection": true } } } @@ -473,7 +249,7 @@ "name": "estimatedDocumentCount", "object": "collection0", "expectError": { - "errorCode": 8 + "isError": true } } ], @@ -495,50 +271,41 @@ ] }, { - "description": "estimatedDocumentCount errors correctly on less than 4.9.0--socket error", + "description": "estimatedDocumentCount works correctly on views", "runOnRequirements": [ { - "minServerVersion": "4.0.0", - "maxServerVersion": "4.8.99", - "topologies": [ - "single", - "replicaset" - ] - }, - { - "minServerVersion": "4.2.0", - "maxServerVersion": "4.8.99", - "topologies": [ - "sharded" - ] + "minServerVersion": "3.4.0" } ], "operations": [ { - "name": "failPoint", - "object": "testRunner", + "name": "dropCollection", + "object": "database0", "arguments": { - "client": "client0", - "failPoint": { - "configureFailPoint": "failCommand", - "mode": { - "times": 1 - }, - "data": { - "failCommands": [ - "count" - ], - "closeConnection": true + "collection": "coll0view" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "coll0view", + "viewOn": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } } - } + ] } }, { "name": "estimatedDocumentCount", - "object": "collection0", - "expectError": { - "isError": true - } + "object": "collection0View", + "expectResult": 2 } ], "expectEvents": [ @@ -548,7 +315,35 @@ { "commandStartedEvent": { "command": { - "count": "coll0" + "drop": "coll0view" + }, + "commandName": "drop", + "databaseName": "edc-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "create": "coll0view", + "viewOn": "coll0", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + } + ] + }, + "commandName": "create", + "databaseName": "edc-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "count": "coll0view" }, "commandName": "count", "databaseName": "edc-tests" diff --git a/tests/UnifiedSpecTests/crud/insertMany-comment.json b/tests/UnifiedSpecTests/crud/insertMany-comment.json index 7e835e801..2b4c80b3f 100644 --- a/tests/UnifiedSpecTests/crud/insertMany-comment.json +++ b/tests/UnifiedSpecTests/crud/insertMany-comment.json @@ -166,6 +166,7 @@ "description": "insertMany with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/insertOne-comment.json b/tests/UnifiedSpecTests/crud/insertOne-comment.json index a9f735ab6..dbd83d9f6 100644 --- a/tests/UnifiedSpecTests/crud/insertOne-comment.json +++ b/tests/UnifiedSpecTests/crud/insertOne-comment.json @@ -162,6 +162,7 @@ "description": "insertOne with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/replaceOne-comment.json b/tests/UnifiedSpecTests/crud/replaceOne-comment.json index bcd8aca22..88bee5d7b 100644 --- a/tests/UnifiedSpecTests/crud/replaceOne-comment.json +++ b/tests/UnifiedSpecTests/crud/replaceOne-comment.json @@ -178,6 +178,7 @@ "description": "ReplaceOne with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/updateMany-comment.json b/tests/UnifiedSpecTests/crud/updateMany-comment.json index 641108452..88b8b67f5 100644 --- a/tests/UnifiedSpecTests/crud/updateMany-comment.json +++ b/tests/UnifiedSpecTests/crud/updateMany-comment.json @@ -182,6 +182,7 @@ "description": "UpdateMany with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/crud/updateOne-comment.json b/tests/UnifiedSpecTests/crud/updateOne-comment.json index c18f59cfb..f4ee74db3 100644 --- a/tests/UnifiedSpecTests/crud/updateOne-comment.json +++ b/tests/UnifiedSpecTests/crud/updateOne-comment.json @@ -186,6 +186,7 @@ "description": "UpdateOne with comment - pre 4.4", "runOnRequirements": [ { + "minServerVersion": "3.4.0", "maxServerVersion": "4.2.99" } ], diff --git a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json index 29a0ec4e3..c1c8ecce0 100644 --- a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json +++ b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1-strict.json @@ -613,6 +613,15 @@ }, { "description": "estimatedDocumentCount appends declared API version", + "runOnRequirements": [ + { + "minServerVersion": "5.0.9", + "maxServerVersion": "5.0.99" + }, + { + "minServerVersion": "5.3.2" + } + ], "operations": [ { "name": "estimatedDocumentCount", @@ -627,22 +636,7 @@ { "commandStartedEvent": { "command": { - "aggregate": "test", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ], + "count": "test", "apiVersion": "1", "apiStrict": true, "apiDeprecationErrors": { diff --git a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json index 1f135eea1..a387d0587 100644 --- a/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json +++ b/tests/UnifiedSpecTests/versioned-api/crud-api-version-1.json @@ -604,7 +604,16 @@ ] }, { - "description": "estimatedDocumentCount appends declared API version on 4.9.0 or greater", + "description": "estimatedDocumentCount appends declared API version", + "runOnRequirements": [ + { + "minServerVersion": "5.0.9", + "maxServerVersion": "5.0.99" + }, + { + "minServerVersion": "5.3.2" + } + ], "operations": [ { "name": "estimatedDocumentCount", @@ -619,22 +628,7 @@ { "commandStartedEvent": { "command": { - "aggregate": "test", - "pipeline": [ - { - "$collStats": { - "count": {} - } - }, - { - "$group": { - "_id": 1, - "n": { - "$sum": "$count" - } - } - } - ], + "count": "test", "apiVersion": "1", "apiStrict": { "$$unsetOrMatches": false From 8f2e921e1946d2c1aa2d63a8e43de508ddb2054c Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 19 May 2022 12:55:35 -0400 Subject: [PATCH 148/321] PHPLIB-810: Document behavior for estimatedDocumentCount --- .../MongoDBCollection-estimatedDocumentCount.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/reference/method/MongoDBCollection-estimatedDocumentCount.txt b/docs/reference/method/MongoDBCollection-estimatedDocumentCount.txt index 097e03b41..1a8316293 100644 --- a/docs/reference/method/MongoDBCollection-estimatedDocumentCount.txt +++ b/docs/reference/method/MongoDBCollection-estimatedDocumentCount.txt @@ -50,7 +50,15 @@ Behavior This method returns an estimate of the count of documents in the collection using collection metadata, rather than counting the documents or consulting an index. This method does not take a ``session`` option and cannot be executed -within a transaction. +within a transaction. See +`Count: Behavior `_ +in the MongoDB manual for more information. + +This method is implemented using the :manual:`count ` +command. Due to an oversight in versions 5.0.0-5.0.8 of MongoDB, the ``count`` +command was not included in version "1" of the Stable API. Applications using +this method with the Stable API are recommended to upgrade their server version +to 5.0.9+ or disable strict mode to avoid encountering errors. See Also -------- From dbb5940d6a0b973145058a58af0a1ec49680c544 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 23 May 2022 13:56:31 -0400 Subject: [PATCH 149/321] PHPLIB-868: Add MongoDB 5.0 to load balancer CI matrix (#932) Also removes remnants of service ID mocking (PHPC-2053). --- .evergreen/config.yml | 6 ++---- .evergreen/run-tests.sh | 7 ------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 9435849de..2ef003753 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -247,7 +247,7 @@ functions: export KMS_TLS_CA_FILE="${client_side_encryption_kms_tls_ca_file}" export KMS_TLS_CERTIFICATE_KEY_FILE="${client_side_encryption_kms_tls_certificate_key_file}" export PATH="${PHP_PATH}/bin:$PATH" - MOCK_SERVICE_ID=${MOCK_SERVICE_ID} API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run atlas data lake test": - command: shell.exec @@ -752,9 +752,7 @@ buildvariants: - .serverless - matrix_name: "test-loadBalanced" - # TODO: Add "5.2" server version alongside "latest" following its GA release - # TODO: Revert driver-version to latest-stable after PHPC 1.13.0 is released (for CDRIVER-4207) - matrix_spec: { "versions": "latest", "php-edge-versions": "latest-stable", "driver-versions": "latest-dev" } + matrix_spec: { "versions": ["5.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Load balanced - ${versions}" run_on: debian92-test tasks: diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 93a574a38..82c01c461 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -6,13 +6,11 @@ set -o errexit # Exit the script with error if any of the commands fail # MONGODB_URI Set the suggested connection MONGODB_URI (including credentials and topology info) # API_VERSION Optional API_VERSION environment variable for run-tests.php # IS_MATRIX_TESTING Set to "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked. -# MOCK_SERVICE_ID Set to "1" to enable service ID mocking for load balancers. Defaults to empty string. SSL=${SSL:-nossl} MONGODB_URI=${MONGODB_URI:-} API_VERSION=${API_VERSION:-} IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} -MOCK_SERVICE_ID=${MOCK_SERVICE_ID:-} # For matrix testing, we have to determine the correct driver version if [ "${IS_MATRIX_TESTING}" = "true" ]; then @@ -46,11 +44,6 @@ fi # Enable verbose output to see skipped and incomplete tests PHPUNIT_OPTS="${PHPUNIT_OPTS} -v" -# For load balancer testing, we need to enable service ID mocking -if [ "${MOCK_SERVICE_ID}" = "1" ]; then - PHPUNIT_OPTS="${PHPUNIT_OPTS} -d mongodb.mock_service_id=1" -fi - # Determine if MONGODB_URI already has a query string SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat) From 62ffb4dd52db82da23faaf4138577979dd0c41d1 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Tue, 24 May 2022 21:50:28 +0300 Subject: [PATCH 150/321] PHPLIB-858: Add MongoDB 6.0 to GitHub CI matrix (#934) --- .github/workflows/tests.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dae42b290..293862ccd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,6 +31,16 @@ jobs: topology: - "server" include: + - os: "ubuntu-20.04" + php-version: "8.0" + mongodb-version: "6.0" + driver-version: "mongodb/mongo-php-driver@master" + topology: "replica_set" + - os: "ubuntu-20.04" + php-version: "8.0" + mongodb-version: "6.0" + driver-version: "mongodb/mongo-php-driver@master" + topology: "sharded_cluster" - os: "ubuntu-20.04" php-version: "8.0" mongodb-version: "5.0" From f2cfb9ff118f6e377b5449c7a26f48d4052d4ca7 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 31 May 2022 11:59:02 -0400 Subject: [PATCH 151/321] PHPLIB-879: Convert command monitoring tests to unified format (#933) Synced with mongodb/specifications@c51e7373aab211ed673061bd6fdb542f655e413d --- tests/SpecTests/CommandExpectations.php | 5 - tests/SpecTests/CommandMonitoringSpecTest.php | 229 ------- tests/SpecTests/Operation.php | 14 - .../command-monitoring/bulkWrite.json | 110 ---- .../SpecTests/command-monitoring/command.json | 113 ---- .../command-monitoring/deleteMany.json | 115 ---- .../command-monitoring/deleteOne.json | 115 ---- tests/SpecTests/command-monitoring/find.json | 559 ------------------ .../command-monitoring/insertMany.json | 145 ----- .../command-monitoring/insertOne.json | 97 --- .../unacknowledgedBulkWrite.json | 69 --- .../command-monitoring/updateMany.json | 135 ----- .../command-monitoring/updateOne.json | 190 ------ .../command-monitoring/bulkWrite.json | 154 +++++ .../command-monitoring/command.json | 83 +++ .../command-monitoring/deleteMany.json | 162 +++++ .../command-monitoring/deleteOne.json | 162 +++++ .../command-monitoring/find.json | 484 +++++++++++++++ .../command-monitoring/insertMany.json | 148 +++++ .../command-monitoring/insertOne.json | 144 +++++ .../unacknowledgedBulkWrite.json | 108 ++++ .../command-monitoring/updateMany.json | 188 ++++++ .../command-monitoring/updateOne.json | 260 ++++++++ 23 files changed, 1893 insertions(+), 1896 deletions(-) delete mode 100644 tests/SpecTests/CommandMonitoringSpecTest.php delete mode 100644 tests/SpecTests/command-monitoring/bulkWrite.json delete mode 100644 tests/SpecTests/command-monitoring/command.json delete mode 100644 tests/SpecTests/command-monitoring/deleteMany.json delete mode 100644 tests/SpecTests/command-monitoring/deleteOne.json delete mode 100644 tests/SpecTests/command-monitoring/find.json delete mode 100644 tests/SpecTests/command-monitoring/insertMany.json delete mode 100644 tests/SpecTests/command-monitoring/insertOne.json delete mode 100644 tests/SpecTests/command-monitoring/unacknowledgedBulkWrite.json delete mode 100644 tests/SpecTests/command-monitoring/updateMany.json delete mode 100644 tests/SpecTests/command-monitoring/updateOne.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/bulkWrite.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/command.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/deleteMany.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/deleteOne.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/find.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/insertMany.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/insertOne.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/unacknowledgedBulkWrite.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/updateMany.json create mode 100644 tests/UnifiedSpecTests/command-monitoring/updateOne.json diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index b33979851..d5b3e2a76 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -81,11 +81,6 @@ public static function fromClientSideEncryption(array $expectedEvents) return $o; } - public static function fromCommandMonitoring(array $expectedEvents) - { - return new self($expectedEvents); - } - public static function fromCrud(array $expectedEvents) { $o = new self($expectedEvents); diff --git a/tests/SpecTests/CommandMonitoringSpecTest.php b/tests/SpecTests/CommandMonitoringSpecTest.php deleted file mode 100644 index bf1c73177..000000000 --- a/tests/SpecTests/CommandMonitoringSpecTest.php +++ /dev/null @@ -1,229 +0,0 @@ -getMore) && $expected->getMore === 42) { - static::assertObjectHasAttribute('getMore', $actual); - static::assertThat($actual->getMore, static::logicalOr( - static::isInstanceOf(Int64::class), - static::isType('integer') - )); - unset($expected->getMore); - } - - if (isset($expected->killCursors) && isset($expected->cursors) && is_array($expected->cursors)) { - static::assertObjectHasAttribute('cursors', $actual); - static::assertIsArray($actual->cursors); - - foreach ($expected->cursors as $i => $cursorId) { - static::assertArrayHasKey($i, $actual->cursors); - - if ($cursorId === 42) { - static::assertThat($actual->cursors[$i], static::logicalOr( - static::isInstanceOf(Int64::class), - static::isType('integer') - )); - } - } - - unset($expected->cursors); - } - - static::assertDocumentsMatch($expected, $actual); - } - - /** - * Assert that the expected and actual command reply documents match. - * - * Note: this method may modify the $expectedReply object. - * - * @param stdClass $expected Expected command reply document - * @param stdClass $actual Actual command reply document - */ - public static function assertCommandReplyMatches(stdClass $expected, stdClass $actual): void - { - if (isset($expected->cursor->id) && $expected->cursor->id === 42) { - static::assertObjectHasAttribute('cursor', $actual); - static::assertIsObject($actual->cursor); - static::assertObjectHasAttribute('id', $actual->cursor); - static::assertThat($actual->cursor->id, static::logicalOr( - static::isInstanceOf(Int64::class), - static::isType('integer') - )); - unset($expected->cursor->id); - } - - if (isset($expected->cursorsUnknown) && is_array($expected->cursorsUnknown)) { - static::assertObjectHasAttribute('cursorsUnknown', $actual); - static::assertIsArray($actual->cursorsUnknown); - - foreach ($expected->cursorsUnknown as $i => $cursorId) { - static::assertArrayHasKey($i, $actual->cursorsUnknown); - - if ($cursorId === 42) { - static::assertThat($actual->cursorsUnknown[$i], static::logicalOr( - static::isInstanceOf(Int64::class), - static::isType('integer') - )); - } - } - - unset($expected->cursorsUnknown); - } - - if (isset($expected->ok) && is_numeric($expected->ok)) { - static::assertObjectHasAttribute('ok', $actual); - static::assertIsNumeric($actual->ok); - static::assertEquals($expected->ok, $actual->ok); - unset($expected->ok); - } - - if (isset($expected->writeErrors) && is_array($expected->writeErrors)) { - static::assertObjectHasAttribute('writeErrors', $actual); - static::assertIsArray($actual->writeErrors); - - foreach ($expected->writeErrors as $i => $expectedWriteError) { - static::assertArrayHasKey($i, $actual->writeErrors); - $actualWriteError = $actual->writeErrors[$i]; - - if (isset($expectedWriteError->code) && $expectedWriteError->code === 42) { - static::assertObjectHasAttribute('code', $actualWriteError); - static::assertThat($actualWriteError->code, static::logicalOr( - static::isInstanceOf(Int64::class), - static::isType('integer') - )); - unset($expected->writeErrors[$i]->code); - } - - if (isset($expectedWriteError->errmsg) && $expectedWriteError->errmsg === '') { - static::assertObjectHasAttribute('errmsg', $actualWriteError); - static::assertIsString($actualWriteError->errmsg); - static::assertNotEmpty($actualWriteError->errmsg); - unset($expected->writeErrors[$i]->errmsg); - } - } - } - - static::assertDocumentsMatch($expected, $actual); - } - - /** - * Execute an individual test case from the specification. - * - * @dataProvider provideTests - * @param stdClass $test Individual "tests[]" document - * @param array $data Top-level "data" array to initialize collection - * @param string $databaseName Name of database under test - * @param string $collectionName Name of collection under test - */ - public function testCommandMonitoring(stdClass $test, array $data, ?string $databaseName = null, ?string $collectionName = null): void - { - $this->checkServerRequirements($this->createRunOn($test)); - - $databaseName = $databaseName ?? $this->getDatabaseName(); - $collectionName = $collectionName ?? $this->getCollectionName(); - - $context = Context::fromCommandMonitoring($test, $databaseName, $collectionName); - $this->setContext($context); - - $this->dropTestAndOutcomeCollections(); - $this->insertDataFixtures($data); - - if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromCommandMonitoring($test->expectations); - $commandExpectations->startMonitoring(); - } - - Operation::fromCommandMonitoring($test->operation)->assert($this, $context); - - if (isset($commandExpectations)) { - $commandExpectations->stopMonitoring(); - $commandExpectations->assert($this, $context); - } - } - - public function provideTests() - { - $testArgs = []; - - foreach (glob(__DIR__ . '/command-monitoring/*.json') as $filename) { - $json = $this->decodeJson(file_get_contents($filename)); - $group = basename($filename, '.json'); - $data = $json->data ?? []; - // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - $databaseName = $json->database_name ?? null; - $collectionName = $json->collection_name ?? null; - // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - - foreach ($json->tests as $test) { - $name = $group . ': ' . $test->description; - $testArgs[$name] = [$test, $data, $databaseName, $collectionName]; - } - } - - return $testArgs; - } - - /** - * Convert the server and topology requirements to a standard "runOn" array - * used by other specifications. - * - * @param stdClass $test - * @return array - */ - private function createRunOn(stdClass $test): array - { - $req = new stdClass(); - - $topologies = [ - self::TOPOLOGY_SINGLE, - self::TOPOLOGY_REPLICASET, - self::TOPOLOGY_SHARDED, - ]; - - // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - /* Append ".99" as patch version, since command monitoring tests expect - * the minor version to be an inclusive upper bound. */ - if (isset($test->ignore_if_server_version_greater_than)) { - $req->maxServerVersion = $test->ignore_if_server_version_greater_than . '.99'; - } - - if (isset($test->ignore_if_server_version_less_than)) { - $req->minServerVersion = $test->ignore_if_server_version_less_than; - } - - if (isset($test->ignore_if_topology_type)) { - $req->topology = array_diff($topologies, $test->ignore_if_topology_type); - } - - // phpcs:enable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps - - return [$req]; - } -} diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index 82f2fa65f..2eede96f2 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -96,20 +96,6 @@ public static function fromClientSideEncryption(stdClass $operation) return $o; } - public static function fromCommandMonitoring(stdClass $operation) - { - $o = new self($operation); - - if (isset($operation->collectionOptions)) { - $o->collectionOptions = (array) $operation->collectionOptions; - } - - /* We purposefully avoid setting a default error expectation, because - * some tests may trigger a write or command error. */ - - return $o; - } - /** * This method is exclusively used to prepare nested operations for the * withTransaction session operation diff --git a/tests/SpecTests/command-monitoring/bulkWrite.json b/tests/SpecTests/command-monitoring/bulkWrite.json deleted file mode 100644 index ca5a9a105..000000000 --- a/tests/SpecTests/command-monitoring/bulkWrite.json +++ /dev/null @@ -1,110 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful mixed bulk write", - "operation": { - "name": "bulkWrite", - "arguments": { - "requests": [ - { - "name": "insertOne", - "arguments": { - "document": { - "_id": 4, - "x": 44 - } - } - }, - { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 3 - }, - "update": { - "$set": { - "x": 333 - } - } - } - } - ] - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 4, - "x": 44 - } - ], - "ordered": true - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "insert" - } - }, - { - "command_started_event": { - "command": { - "update": "test", - "updates": [ - { - "q": { - "_id": 3 - }, - "u": { - "$set": { - "x": 333 - } - } - } - ], - "ordered": true - }, - "command_name": "update", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "update" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/command.json b/tests/SpecTests/command-monitoring/command.json deleted file mode 100644 index 7e1e347be..000000000 --- a/tests/SpecTests/command-monitoring/command.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful command", - "operation": { - "name": "count", - "arguments": { - "filter": { - "_id": 1 - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "count": "test", - "query": { - "_id": 1 - } - }, - "command_name": "count", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "count" - } - } - ] - }, - { - "description": "A failed command event", - "operation": { - "name": "count", - "arguments": { - "filter": { - "$or": true - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "count": "test", - "query": { - "$or": true - } - }, - "command_name": "count", - "database_name": "command-monitoring-tests" - } - }, - { - "command_failed_event": { - "command_name": "count" - } - } - ] - }, - { - "description": "A successful command with a non-primary read preference", - "operation": { - "name": "count", - "arguments": { - "filter": { - "_id": 1 - } - }, - "read_preference": { - "mode": "primaryPreferred" - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "count": "test", - "query": { - "_id": 1 - } - }, - "command_name": "count", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "count" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/deleteMany.json b/tests/SpecTests/command-monitoring/deleteMany.json deleted file mode 100644 index 7cd396806..000000000 --- a/tests/SpecTests/command-monitoring/deleteMany.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful delete many", - "operation": { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "test", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "limit": 0 - } - ], - "ordered": true - }, - "command_name": "delete", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 2 - }, - "command_name": "delete" - } - } - ] - }, - { - "description": "A successful delete many command with write errors", - "operation": { - "name": "deleteMany", - "arguments": { - "filter": { - "_id": { - "$nothing": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "test", - "deletes": [ - { - "q": { - "_id": { - "$nothing": 1 - } - }, - "limit": 0 - } - ], - "ordered": true - }, - "command_name": "delete", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 0, - "writeErrors": [ - { - "index": 0, - "code": 42, - "errmsg": "" - } - ] - }, - "command_name": "delete" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/deleteOne.json b/tests/SpecTests/command-monitoring/deleteOne.json deleted file mode 100644 index 0971dfcf2..000000000 --- a/tests/SpecTests/command-monitoring/deleteOne.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful delete one", - "operation": { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "test", - "deletes": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "limit": 1 - } - ], - "ordered": true - }, - "command_name": "delete", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "delete" - } - } - ] - }, - { - "description": "A successful delete one command with write errors", - "operation": { - "name": "deleteOne", - "arguments": { - "filter": { - "_id": { - "$nothing": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "delete": "test", - "deletes": [ - { - "q": { - "_id": { - "$nothing": 1 - } - }, - "limit": 1 - } - ], - "ordered": true - }, - "command_name": "delete", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 0, - "writeErrors": [ - { - "index": 0, - "code": 42, - "errmsg": "" - } - ] - }, - "command_name": "delete" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/find.json b/tests/SpecTests/command-monitoring/find.json deleted file mode 100644 index e2bb95306..000000000 --- a/tests/SpecTests/command-monitoring/find.json +++ /dev/null @@ -1,559 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - }, - { - "_id": 4, - "x": 44 - }, - { - "_id": 5, - "x": 55 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "namespace": "command-monitoring-tests.test", - "tests": [ - { - "description": "A successful find event with no options", - "operation": { - "name": "find", - "arguments": { - "filter": { - "_id": 1 - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test", - "filter": { - "_id": 1 - } - }, - "command_name": "find", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "0" - }, - "ns": "command-monitoring-tests.test", - "firstBatch": [ - { - "_id": 1, - "x": 11 - } - ] - } - }, - "command_name": "find" - } - } - ] - }, - { - "description": "A successful find event with options", - "operation": { - "name": "find", - "read_preference": { - "mode": "primaryPreferred" - }, - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "sort": { - "_id": 1 - }, - "skip": { - "$numberLong": "2" - }, - "comment": "test", - "hint": { - "_id": 1 - }, - "max": { - "_id": 6 - }, - "maxTimeMS": 6000, - "min": { - "_id": 0 - }, - "returnKey": false, - "showRecordId": false - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test", - "filter": { - "_id": { - "$gt": 1 - } - }, - "sort": { - "_id": 1 - }, - "skip": { - "$numberLong": "2" - }, - "comment": "test", - "hint": { - "_id": 1 - }, - "max": { - "_id": 6 - }, - "maxTimeMS": 6000, - "min": { - "_id": 0 - }, - "returnKey": false, - "showRecordId": false - }, - "command_name": "find", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "0" - }, - "ns": "command-monitoring-tests.test", - "firstBatch": [ - { - "_id": 4, - "x": 44 - }, - { - "_id": 5, - "x": 55 - } - ] - } - }, - "command_name": "find" - } - } - ] - }, - { - "description": "A successful find event with a getmore", - "operation": { - "name": "find", - "arguments": { - "filter": { - "_id": { - "$gte": 1 - } - }, - "sort": { - "_id": 1 - }, - "batchSize": { - "$numberLong": "3" - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test", - "filter": { - "_id": { - "$gte": 1 - } - }, - "sort": { - "_id": 1 - }, - "batchSize": { - "$numberLong": "3" - } - }, - "command_name": "find", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "42" - }, - "ns": "command-monitoring-tests.test", - "firstBatch": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - }, - "command_name": "find" - } - }, - { - "command_started_event": { - "command": { - "getMore": { - "$numberLong": "42" - }, - "collection": "test", - "batchSize": { - "$numberLong": "3" - } - }, - "command_name": "getMore", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "0" - }, - "ns": "command-monitoring-tests.test", - "nextBatch": [ - { - "_id": 4, - "x": 44 - }, - { - "_id": 5, - "x": 55 - } - ] - } - }, - "command_name": "getMore" - } - } - ] - }, - { - "description": "A successful find event with a getmore and killcursors", - "ignore_if_server_version_greater_than": "3.0", - "operation": { - "name": "find", - "arguments": { - "filter": { - "_id": { - "$gte": 1 - } - }, - "sort": { - "_id": 1 - }, - "batchSize": { - "$numberLong": "3" - }, - "limit": { - "$numberLong": "4" - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test", - "filter": { - "_id": { - "$gte": 1 - } - }, - "sort": { - "_id": 1 - }, - "batchSize": { - "$numberLong": "3" - }, - "limit": { - "$numberLong": "4" - } - }, - "command_name": "find", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "42" - }, - "ns": "command-monitoring-tests.test", - "firstBatch": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - }, - "command_name": "find" - } - }, - { - "command_started_event": { - "command": { - "getMore": { - "$numberLong": "42" - }, - "collection": "test", - "batchSize": { - "$numberLong": "1" - } - }, - "command_name": "getMore", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "42" - }, - "ns": "command-monitoring-tests.test", - "nextBatch": [ - { - "_id": 4, - "x": 44 - } - ] - } - }, - "command_name": "getMore" - } - }, - { - "command_started_event": { - "command": { - "killCursors": "test", - "cursors": [ - { - "$numberLong": "42" - } - ] - }, - "command_name": "killCursors", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursorsUnknown": [ - { - "$numberLong": "42" - } - ] - }, - "command_name": "killCursors" - } - } - ] - }, - { - "description": "A successful find event with a getmore and the server kills the cursor (<= 4.4)", - "ignore_if_server_version_less_than": "3.1", - "ignore_if_server_version_greater_than": "4.4", - "ignore_if_topology_type": [ - "sharded" - ], - "operation": { - "name": "find", - "arguments": { - "filter": { - "_id": { - "$gte": 1 - } - }, - "sort": { - "_id": 1 - }, - "batchSize": { - "$numberLong": "3" - }, - "limit": { - "$numberLong": "4" - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test", - "filter": { - "_id": { - "$gte": 1 - } - }, - "sort": { - "_id": 1 - }, - "batchSize": { - "$numberLong": "3" - }, - "limit": { - "$numberLong": "4" - } - }, - "command_name": "find", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "42" - }, - "ns": "command-monitoring-tests.test", - "firstBatch": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ] - } - }, - "command_name": "find" - } - }, - { - "command_started_event": { - "command": { - "getMore": { - "$numberLong": "42" - }, - "collection": "test", - "batchSize": { - "$numberLong": "1" - } - }, - "command_name": "getMore", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "cursor": { - "id": { - "$numberLong": "0" - }, - "ns": "command-monitoring-tests.test", - "nextBatch": [ - { - "_id": 4, - "x": 44 - } - ] - } - }, - "command_name": "getMore" - } - } - ] - }, - { - "description": "A failed find event", - "operation": { - "name": "find", - "arguments": { - "filter": { - "$or": true - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "find": "test", - "filter": { - "$or": true - } - }, - "command_name": "find", - "database_name": "command-monitoring-tests" - } - }, - { - "command_failed_event": { - "command_name": "find" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/insertMany.json b/tests/SpecTests/command-monitoring/insertMany.json deleted file mode 100644 index 0becf928e..000000000 --- a/tests/SpecTests/command-monitoring/insertMany.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful insert many", - "operation": { - "name": "insertMany", - "arguments": { - "documents": [ - { - "_id": 2, - "x": 22 - } - ] - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 2, - "x": 22 - } - ], - "ordered": true - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "insert" - } - } - ] - }, - { - "description": "A successful insert many command with write errors", - "operation": { - "name": "insertMany", - "arguments": { - "documents": [ - { - "_id": 1, - "x": 11 - } - ] - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 1, - "x": 11 - } - ], - "ordered": true - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 0, - "writeErrors": [ - { - "index": 0, - "code": 42, - "errmsg": "" - } - ] - }, - "command_name": "insert" - } - } - ] - }, - { - "description": "A successful unordered insert many", - "operation": { - "name": "insertMany", - "arguments": { - "documents": [ - { - "_id": 2, - "x": 22 - } - ], - "options": { - "ordered": false - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 2, - "x": 22 - } - ], - "ordered": false - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "insert" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/insertOne.json b/tests/SpecTests/command-monitoring/insertOne.json deleted file mode 100644 index 877bca1a6..000000000 --- a/tests/SpecTests/command-monitoring/insertOne.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful insert one", - "operation": { - "name": "insertOne", - "arguments": { - "document": { - "_id": 2, - "x": 22 - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 2, - "x": 22 - } - ], - "ordered": true - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "insert" - } - } - ] - }, - { - "description": "A successful insert one command with write errors", - "operation": { - "name": "insertOne", - "arguments": { - "document": { - "_id": 1, - "x": 11 - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test", - "documents": [ - { - "_id": 1, - "x": 11 - } - ], - "ordered": true - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 0, - "writeErrors": [ - { - "index": 0, - "code": 42, - "errmsg": "" - } - ] - }, - "command_name": "insert" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/unacknowledgedBulkWrite.json b/tests/SpecTests/command-monitoring/unacknowledgedBulkWrite.json deleted file mode 100644 index ae116289e..000000000 --- a/tests/SpecTests/command-monitoring/unacknowledgedBulkWrite.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - } - ], - "collection_name": "test-unacknowledged-bulk-write", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful unordered bulk write with an unacknowledged write concern", - "comment": "On a 2.4 server, no GLE is sent and requires a client-side manufactured reply", - "operation": { - "name": "bulkWrite", - "collectionOptions": { - "writeConcern": { - "w": 0 - } - }, - "arguments": { - "requests": [ - { - "name": "insertOne", - "arguments": { - "document": { - "_id": "unorderedBulkWriteInsertW0", - "x": 44 - } - } - } - ], - "options": { - "ordered": false - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "insert": "test-unacknowledged-bulk-write", - "documents": [ - { - "_id": "unorderedBulkWriteInsertW0", - "x": 44 - } - ], - "ordered": false, - "writeConcern": { - "w": 0 - } - }, - "command_name": "insert", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1 - }, - "command_name": "insert" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/updateMany.json b/tests/SpecTests/command-monitoring/updateMany.json deleted file mode 100644 index d82792fc4..000000000 --- a/tests/SpecTests/command-monitoring/updateMany.json +++ /dev/null @@ -1,135 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful update many", - "operation": { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "ordered": true, - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - }, - "multi": true - } - ] - }, - "command_name": "update", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 2 - }, - "command_name": "update" - } - } - ] - }, - { - "description": "A successful update many command with write errors", - "operation": { - "name": "updateMany", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$nothing": { - "x": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "ordered": true, - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$nothing": { - "x": 1 - } - }, - "multi": true - } - ] - }, - "command_name": "update", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 0, - "writeErrors": [ - { - "index": 0, - "code": 42, - "errmsg": "" - } - ] - }, - "command_name": "update" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/command-monitoring/updateOne.json b/tests/SpecTests/command-monitoring/updateOne.json deleted file mode 100644 index ba41dbb0c..000000000 --- a/tests/SpecTests/command-monitoring/updateOne.json +++ /dev/null @@ -1,190 +0,0 @@ -{ - "data": [ - { - "_id": 1, - "x": 11 - }, - { - "_id": 2, - "x": 22 - }, - { - "_id": 3, - "x": 33 - } - ], - "collection_name": "test", - "database_name": "command-monitoring-tests", - "tests": [ - { - "description": "A successful update one", - "operation": { - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$inc": { - "x": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "ordered": true, - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$inc": { - "x": 1 - } - } - } - ] - }, - "command_name": "update", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1 - }, - "command_name": "update" - } - } - ] - }, - { - "description": "A successful update one with upsert when the upserted id is not an object id", - "operation": { - "name": "updateOne", - "arguments": { - "filter": { - "_id": 4 - }, - "update": { - "$inc": { - "x": 1 - } - }, - "upsert": true - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "ordered": true, - "updates": [ - { - "q": { - "_id": 4 - }, - "u": { - "$inc": { - "x": 1 - } - }, - "upsert": true - } - ] - }, - "command_name": "update", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 1, - "upserted": [ - { - "index": 0, - "_id": 4 - } - ] - }, - "command_name": "update" - } - } - ] - }, - { - "description": "A successful update one command with write errors", - "operation": { - "name": "updateOne", - "arguments": { - "filter": { - "_id": { - "$gt": 1 - } - }, - "update": { - "$nothing": { - "x": 1 - } - } - } - }, - "expectations": [ - { - "command_started_event": { - "command": { - "update": "test", - "ordered": true, - "updates": [ - { - "q": { - "_id": { - "$gt": 1 - } - }, - "u": { - "$nothing": { - "x": 1 - } - } - } - ] - }, - "command_name": "update", - "database_name": "command-monitoring-tests" - } - }, - { - "command_succeeded_event": { - "reply": { - "ok": 1, - "n": 0, - "writeErrors": [ - { - "index": 0, - "code": 42, - "errmsg": "" - } - ] - }, - "command_name": "update" - } - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/command-monitoring/bulkWrite.json b/tests/UnifiedSpecTests/command-monitoring/bulkWrite.json new file mode 100644 index 000000000..49c728442 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/bulkWrite.json @@ -0,0 +1,154 @@ +{ + "description": "bulkWrite", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "A successful mixed bulk write", + "operations": [ + { + "name": "bulkWrite", + "object": "collection", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 4, + "x": 44 + } + } + }, + { + "updateOne": { + "filter": { + "_id": 3 + }, + "update": { + "$set": { + "x": 333 + } + } + } + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 4, + "x": 44 + } + ], + "ordered": true + }, + "commandName": "insert", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1 + }, + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 3 + }, + "u": { + "$set": { + "x": 333 + } + }, + "upsert": { + "$$unsetOrMatches": false + }, + "multi": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1 + }, + "commandName": "update" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/command.json b/tests/UnifiedSpecTests/command-monitoring/command.json new file mode 100644 index 000000000..c28af95fe --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/command.json @@ -0,0 +1,83 @@ +{ + "description": "command", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "A successful command", + "operations": [ + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "ping": 1 + }, + "commandName": "ping" + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "ping": 1 + }, + "commandName": "ping", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1 + }, + "commandName": "ping" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/deleteMany.json b/tests/UnifiedSpecTests/command-monitoring/deleteMany.json new file mode 100644 index 000000000..78ebad1f9 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/deleteMany.json @@ -0,0 +1,162 @@ +{ + "description": "deleteMany", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "A successful deleteMany", + "operations": [ + { + "name": "deleteMany", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 0 + } + ], + "ordered": true + }, + "commandName": "delete", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 2 + }, + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "A successful deleteMany with write errors", + "operations": [ + { + "name": "deleteMany", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$unsupported": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": { + "$unsupported": 1 + } + }, + "limit": 0 + } + ], + "ordered": true + }, + "commandName": "delete", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 0, + "writeErrors": { + "$$type": "array" + } + }, + "commandName": "delete" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/deleteOne.json b/tests/UnifiedSpecTests/command-monitoring/deleteOne.json new file mode 100644 index 000000000..2420794fe --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/deleteOne.json @@ -0,0 +1,162 @@ +{ + "description": "deleteOne", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "A successful deleteOne", + "operations": [ + { + "name": "deleteOne", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "limit": 1 + } + ], + "ordered": true + }, + "commandName": "delete", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1 + }, + "commandName": "delete" + } + } + ] + } + ] + }, + { + "description": "A successful deleteOne with write errors", + "operations": [ + { + "name": "deleteOne", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$unsupported": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "test", + "deletes": [ + { + "q": { + "_id": { + "$unsupported": 1 + } + }, + "limit": 1 + } + ], + "ordered": true + }, + "commandName": "delete", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 0, + "writeErrors": { + "$$type": "array" + } + }, + "commandName": "delete" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/find.json b/tests/UnifiedSpecTests/command-monitoring/find.json new file mode 100644 index 000000000..13dd9697f --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/find.json @@ -0,0 +1,484 @@ +{ + "description": "find", + "schemaVersion": "1.1", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "_yamlAnchors": { + "namespace": "command-monitoring-tests.test" + }, + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + }, + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + ], + "tests": [ + { + "description": "A successful find with no options", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": 1 + } + }, + "commandName": "find", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": 0, + "ns": "command-monitoring-tests.test", + "firstBatch": [ + { + "_id": 1, + "x": 11 + } + ] + } + }, + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "A successful find with options", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "sort": { + "_id": 1 + }, + "skip": 2, + "comment": "test", + "hint": { + "_id": 1 + }, + "max": { + "_id": 6 + }, + "maxTimeMS": 6000, + "min": { + "_id": 0 + }, + "returnKey": false, + "showRecordId": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": { + "$gt": 1 + } + }, + "sort": { + "_id": 1 + }, + "skip": 2, + "comment": "test", + "hint": { + "_id": 1 + }, + "max": { + "_id": 6 + }, + "maxTimeMS": 6000, + "min": { + "_id": 0 + }, + "returnKey": false, + "showRecordId": false + }, + "commandName": "find", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": 0, + "ns": "command-monitoring-tests.test", + "firstBatch": [ + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + }, + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "A successful find with a getMore", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gte": 1 + } + }, + "sort": { + "_id": 1 + }, + "batchSize": 3 + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": { + "$gte": 1 + } + }, + "sort": { + "_id": 1 + }, + "batchSize": 3 + }, + "commandName": "find", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": { + "$$type": [ + "int", + "long" + ] + }, + "ns": "command-monitoring-tests.test", + "firstBatch": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "test", + "batchSize": 3 + }, + "commandName": "getMore", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": 0, + "ns": "command-monitoring-tests.test", + "nextBatch": [ + { + "_id": 4, + "x": 44 + }, + { + "_id": 5, + "x": 55 + } + ] + } + }, + "commandName": "getMore" + } + } + ] + } + ] + }, + { + "description": "A successful find event with a getmore and the server kills the cursor (<= 4.4)", + "runOnRequirements": [ + { + "minServerVersion": "3.1", + "maxServerVersion": "4.4.99", + "topologies": [ + "single", + "replicaset" + ] + } + ], + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gte": 1 + } + }, + "sort": { + "_id": 1 + }, + "batchSize": 3, + "limit": 4 + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "_id": { + "$gte": 1 + } + }, + "sort": { + "_id": 1 + }, + "batchSize": 3, + "limit": 4 + }, + "commandName": "find", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": { + "$$type": [ + "int", + "long" + ] + }, + "ns": "command-monitoring-tests.test", + "firstBatch": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + }, + "commandName": "find" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": "test", + "batchSize": 1 + }, + "commandName": "getMore", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": 0, + "ns": "command-monitoring-tests.test", + "nextBatch": [ + { + "_id": 4, + "x": 44 + } + ] + } + }, + "commandName": "getMore" + } + } + ] + } + ] + }, + { + "description": "A failed find event", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": { + "$or": true + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "filter": { + "$or": true + } + }, + "commandName": "find", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandFailedEvent": { + "commandName": "find" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/insertMany.json b/tests/UnifiedSpecTests/command-monitoring/insertMany.json new file mode 100644 index 000000000..a80a218c6 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/insertMany.json @@ -0,0 +1,148 @@ +{ + "description": "insertMany", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "A successful insertMany", + "operations": [ + { + "name": "insertMany", + "object": "collection", + "arguments": { + "documents": [ + { + "_id": 2, + "x": 22 + } + ] + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "ordered": true + }, + "commandName": "insert", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1 + }, + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "A successful insertMany with write errors", + "operations": [ + { + "name": "insertMany", + "object": "collection", + "arguments": { + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1, + "x": 11 + } + ], + "ordered": true + }, + "commandName": "insert", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 0, + "writeErrors": { + "$$type": "array" + } + }, + "commandName": "insert" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/insertOne.json b/tests/UnifiedSpecTests/command-monitoring/insertOne.json new file mode 100644 index 000000000..6ff732e41 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/insertOne.json @@ -0,0 +1,144 @@ +{ + "description": "insertOne", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "A successful insertOne", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "arguments": { + "document": { + "_id": 2, + "x": 22 + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "ordered": true + }, + "commandName": "insert", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1 + }, + "commandName": "insert" + } + } + ] + } + ] + }, + { + "description": "A successful insertOne with write errors", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "arguments": { + "document": { + "_id": 1, + "x": 11 + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": 1, + "x": 11 + } + ], + "ordered": true + }, + "commandName": "insert", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 0, + "writeErrors": { + "$$type": "array" + } + }, + "commandName": "insert" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/unacknowledgedBulkWrite.json b/tests/UnifiedSpecTests/command-monitoring/unacknowledgedBulkWrite.json new file mode 100644 index 000000000..4c16d6df1 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/unacknowledgedBulkWrite.json @@ -0,0 +1,108 @@ +{ + "description": "unacknowledgedBulkWrite", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test", + "collectionOptions": { + "writeConcern": { + "w": 0 + } + } + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "A successful unordered bulk write with an unacknowledged write concern", + "operations": [ + { + "name": "bulkWrite", + "object": "collection", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": "unorderedBulkWriteInsertW0", + "x": 44 + } + } + } + ], + "ordered": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "test", + "documents": [ + { + "_id": "unorderedBulkWriteInsertW0", + "x": 44 + } + ], + "ordered": false, + "writeConcern": { + "w": 0 + } + }, + "commandName": "insert", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": { + "$$exists": false + } + }, + "commandName": "insert" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/updateMany.json b/tests/UnifiedSpecTests/command-monitoring/updateMany.json new file mode 100644 index 000000000..b15434226 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/updateMany.json @@ -0,0 +1,188 @@ +{ + "description": "updateMany", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "A successful updateMany", + "operations": [ + { + "name": "updateMany", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "upsert": { + "$$unsetOrMatches": false + }, + "multi": true + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 2 + }, + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "A successful updateMany with write errors", + "operations": [ + { + "name": "updateMany", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$unsupported": { + "x": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$unsupported": { + "x": 1 + } + }, + "upsert": { + "$$unsetOrMatches": false + }, + "multi": true + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 0, + "writeErrors": { + "$$type": "array" + } + }, + "commandName": "update" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/command-monitoring/updateOne.json b/tests/UnifiedSpecTests/command-monitoring/updateOne.json new file mode 100644 index 000000000..a0ae99e88 --- /dev/null +++ b/tests/UnifiedSpecTests/command-monitoring/updateOne.json @@ -0,0 +1,260 @@ +{ + "description": "updateOne", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "database": { + "id": "database", + "client": "client", + "databaseName": "command-monitoring-tests" + } + }, + { + "collection": { + "id": "collection", + "database": "database", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "command-monitoring-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "A successful updateOne", + "operations": [ + { + "name": "updateOne", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$inc": { + "x": 1 + } + } + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$inc": { + "x": 1 + } + }, + "upsert": { + "$$unsetOrMatches": false + }, + "multi": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1 + }, + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "A successful updateOne with upsert where the upserted id is not an ObjectId", + "operations": [ + { + "name": "updateOne", + "object": "collection", + "arguments": { + "filter": { + "_id": 4 + }, + "update": { + "$inc": { + "x": 1 + } + }, + "upsert": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": 4 + }, + "u": { + "$inc": { + "x": 1 + } + }, + "upsert": true, + "multi": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 1, + "upserted": [ + { + "index": 0, + "_id": 4 + } + ] + }, + "commandName": "update" + } + } + ] + } + ] + }, + { + "description": "A successful updateOne with write errors", + "operations": [ + { + "name": "updateOne", + "object": "collection", + "arguments": { + "filter": { + "_id": { + "$gt": 1 + } + }, + "update": { + "$unsupported": { + "x": 1 + } + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "update": "test", + "updates": [ + { + "q": { + "_id": { + "$gt": 1 + } + }, + "u": { + "$unsupported": { + "x": 1 + } + }, + "upsert": { + "$$unsetOrMatches": false + }, + "multi": { + "$$unsetOrMatches": false + } + } + ], + "ordered": true + }, + "commandName": "update", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "n": 0, + "writeErrors": { + "$$type": "array" + } + }, + "commandName": "update" + } + } + ] + } + ] + } + ] +} From 51b5d1f5f0e0c338954e0df087144ba31d691ac0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 2 Jun 2022 16:35:26 -0400 Subject: [PATCH 152/321] PHPLIB-879: Update command monitoring spec tests Synced with mongodb/specifications@bf372a162c304b3f57dccbda00346241ad0cbf17 --- .../command-monitoring/find.json | 90 ++++++++++++++++--- 1 file changed, 78 insertions(+), 12 deletions(-) diff --git a/tests/UnifiedSpecTests/command-monitoring/find.json b/tests/UnifiedSpecTests/command-monitoring/find.json index 13dd9697f..4b5f45ae9 100644 --- a/tests/UnifiedSpecTests/command-monitoring/find.json +++ b/tests/UnifiedSpecTests/command-monitoring/find.json @@ -123,7 +123,11 @@ } }, "sort": { - "_id": 1 + "x": -1 + }, + "projection": { + "_id": 0, + "x": 1 }, "skip": 2, "comment": "test", @@ -136,9 +140,7 @@ "maxTimeMS": 6000, "min": { "_id": 0 - }, - "returnKey": false, - "showRecordId": false + } } } ], @@ -156,7 +158,11 @@ } }, "sort": { - "_id": 1 + "x": -1 + }, + "projection": { + "_id": 0, + "x": 1 }, "skip": 2, "comment": "test", @@ -169,9 +175,7 @@ "maxTimeMS": 6000, "min": { "_id": 0 - }, - "returnKey": false, - "showRecordId": false + } }, "commandName": "find", "databaseName": "command-monitoring-tests" @@ -186,12 +190,74 @@ "ns": "command-monitoring-tests.test", "firstBatch": [ { - "_id": 4, - "x": 44 + "x": 33 }, { - "_id": 5, - "x": 55 + "x": 22 + } + ] + } + }, + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "A successful find with showRecordId and returnKey", + "operations": [ + { + "name": "find", + "object": "collection", + "arguments": { + "filter": {}, + "sort": { + "_id": 1 + }, + "showRecordId": true, + "returnKey": true + } + } + ], + "expectEvents": [ + { + "client": "client", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "test", + "showRecordId": true, + "returnKey": true + }, + "commandName": "find", + "databaseName": "command-monitoring-tests" + } + }, + { + "commandSucceededEvent": { + "reply": { + "ok": 1, + "cursor": { + "id": 0, + "ns": "command-monitoring-tests.test", + "firstBatch": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + }, + { + "_id": 4 + }, + { + "_id": 5 } ] } From 75eae8e89c18434c437fd1c9b8406a4e367a68f0 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Mon, 6 Jun 2022 18:12:02 +0300 Subject: [PATCH 153/321] PHPLIB-852: Update change stream tests for wallTime event field (#937) Synced with mongodb/specifications@1a513fe027afb7706485a1e79c53a96acc2ec22 --- .../change-streams/change-streams.json | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/UnifiedSpecTests/change-streams/change-streams.json b/tests/UnifiedSpecTests/change-streams/change-streams.json index 99f5624ac..c8b60ed4e 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams.json @@ -1748,6 +1748,48 @@ ] } ] + }, + { + "description": "Test wallTime field is set in a change event", + "runOnRequirements": [ + { + "minServerVersion": "6.0.0" + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "wallTime": { + "$$exists": true + } + } + } + ] } ] } From 370b5a23717df5ef6b5e6a03e56629972cb7ce16 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Mon, 6 Jun 2022 18:59:41 +0300 Subject: [PATCH 154/321] PHPLIB-869: Support viewOn and pipeline options in createCollection helper (#935) --- ...tabase-method-createCollection-option.yaml | 31 +++++++++++++++++ src/Operation/CreateCollection.php | 34 ++++++++++++++++++- tests/Operation/CreateCollectionTest.php | 15 ++++++++ tests/UnifiedSpecTests/UnifiedSpecTest.php | 2 -- tests/UnifiedSpecTests/Util.php | 2 +- 5 files changed, 80 insertions(+), 4 deletions(-) diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 9b0ae8a6a..10d9252b3 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -145,6 +145,20 @@ source: file: apiargs-common-option.yaml ref: maxTimeMS --- +arg_name: option +name: pipeline +type: array +description: | + An array that consists of the aggregation pipeline stage(s), which will be + applied to the collection or view specified by ``viewOn``. See the + :manual:`create ` command documentation for more + information. + + .. versionadded:: 1.13 +interface: phpmethod +operation: ~ +optional: true +--- source: file: apiargs-common-option.yaml ref: session @@ -295,6 +309,23 @@ interface: phpmethod operation: ~ optional: true --- +arg_name: option +name: viewOn +type: string +description: | + The name of the source collection or view from which to create the view. + + .. note:: + + The name is not the full namespace of the collection or view (i.e. it does + not include the database name). Views must be created in the same databases + as the source collection or view. + + .. versionadded:: 1.13 +interface: phpmethod +operation: ~ +optional: true +--- source: file: apiargs-MongoDBDatabase-common-option.yaml ref: writeConcern diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index e3819d819..3b748cf61 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -30,6 +30,7 @@ use function is_integer; use function is_object; use function is_string; +use function sprintf; use function trigger_error; use const E_USER_DEPRECATED; @@ -100,6 +101,10 @@ class CreateCollection implements Executable * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * + * * pipeline (array): An array that consists of the aggregation pipeline + * stage(s), which will be applied to the collection or view specified by + * viewOn. + * * * session (MongoDB\Driver\Session): Client session. * * * size (integer): The maximum number of bytes for a capped collection. @@ -119,6 +124,9 @@ class CreateCollection implements Executable * * * validator (document): Validation rules or expressions. * + * * viewOn (string): The name of the source collection or view from which + * to create the view. + * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. * * @see https://source.wiredtiger.com/2.4.1/struct_w_t___s_e_s_s_i_o_n.html#a358ca4141d59c345f401c58501276bbb @@ -170,6 +178,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); } + if (isset($options['pipeline']) && ! is_array($options['pipeline'])) { + throw InvalidArgumentException::invalidType('"pipeline" option', $options['pipeline'], 'array'); + } + if (isset($options['session']) && ! $options['session'] instanceof Session) { throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); } @@ -202,6 +214,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"validator" option', $options['validator'], 'array or object'); } + if (isset($options['viewOn']) && ! is_string($options['viewOn'])) { + throw InvalidArgumentException::invalidType('"viewOn" option', $options['viewOn'], 'string'); + } + if (isset($options['writeConcern']) && ! $options['writeConcern'] instanceof WriteConcern) { throw InvalidArgumentException::invalidType('"writeConcern" option', $options['writeConcern'], WriteConcern::class); } @@ -214,6 +230,22 @@ public function __construct($databaseName, $collectionName, array $options = []) trigger_error('The "autoIndexId" option is deprecated and will be removed in a future release', E_USER_DEPRECATED); } + if (isset($options['pipeline'])) { + $expectedIndex = 0; + + foreach ($options['pipeline'] as $i => $operation) { + if ($i !== $expectedIndex) { + throw new InvalidArgumentException(sprintf('The "pipeline" option is not a list (unexpected index: "%s")', $i)); + } + + if (! is_array($operation) && ! is_object($operation)) { + throw InvalidArgumentException::invalidType(sprintf('$options["pipeline"][%d]', $i), $operation, 'array or object'); + } + + $expectedIndex += 1; + } + } + $this->databaseName = (string) $databaseName; $this->collectionName = (string) $collectionName; $this->options = $options; @@ -247,7 +279,7 @@ private function createCommand() { $cmd = ['create' => $this->collectionName]; - foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'size', 'validationAction', 'validationLevel'] as $option) { + foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'pipeline', 'size', 'validationAction', 'validationLevel', 'viewOn'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index efc6806c3..ec6205fca 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -7,6 +7,13 @@ class CreateCollectionTest extends TestCase { + public function testConstructorPipelineOptionMustBeAList(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "pipeline" option is not a list (unexpected index: "1")'); + new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['pipeline' => [1 => ['$match' => ['x' => 1]]]]); + } + /** * @dataProvider provideInvalidConstructorOptions */ @@ -60,6 +67,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['maxTimeMS' => $value]; } + foreach ($this->getInvalidArrayValues() as $value) { + $options[][] = ['pipeline' => $value]; + } + foreach ($this->getInvalidSessionValues() as $value) { $options[][] = ['session' => $value]; } @@ -92,6 +103,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['validator' => $value]; } + foreach ($this->getInvalidStringValues() as $value) { + $options[][] = ['viewOn' => $value]; + } + foreach ($this->getInvalidWriteConcernValues() as $value) { $options[][] = ['writeConcern' => $value]; } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 1b735d6da..9fe809ebe 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -111,8 +111,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', 'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - // CreateCollection "viewOn" and "pipeline" options are not yet implemented - 'crud/estimatedDocumentCount: estimatedDocumentCount works correctly on views' => 'Not yet implemented (PHPLIB-869)', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 98c617dcc..82047934c 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -62,7 +62,7 @@ final class Util Database::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], - 'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator'], + 'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'pipeline', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator', 'viewOn'], 'dropCollection' => ['collection', 'session'], 'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], 'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], From 09d194a61816413aadee7aac948f67f4419d0f3a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 25 May 2022 14:51:18 -0400 Subject: [PATCH 155/321] Apply numbering to CSFLE prose tests --- .../ClientSideEncryptionSpecTest.php | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 587b71bc0..81989733e 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -182,8 +182,9 @@ public function provideTests() } /** - * Prose test: Data key and double encryption + * Prose test 2: Data Key and Double Encryption * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#data-key-and-double-encryption * @dataProvider dataKeyProvider */ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey): void @@ -320,8 +321,9 @@ public static function dataKeyProvider() } /** - * Prose test: External Key Vault + * Prose test 3: External Key Vault * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#external-key-vault-test * @testWith [false] * [true] */ @@ -471,8 +473,9 @@ static function (self $test, Collection $collection, array $document): void { } /** - * Prose test: BSON size limits and batch splitting + * Prose test 4: BSON Size Limits and Batch Splitting * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#bson-size-limits-and-batch-splitting * @dataProvider provideBSONSizeLimitsAndBatchSplittingTests */ public function testBSONSizeLimitsAndBatchSplitting(Closure $test): void @@ -505,7 +508,9 @@ public function testBSONSizeLimitsAndBatchSplitting(Closure $test): void } /** - * Prose test: Views are prohibited + * Prose test 5: Views Are Prohibited + * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#views-are-prohibited */ public function testViewsAreProhibited(): void { @@ -535,8 +540,9 @@ public function testViewsAreProhibited(): void } /** - * Prose test: BSON Corpus + * Prose test 6: BSON Corpus * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#corpus-test * @testWith [true] * [false] */ @@ -647,8 +653,9 @@ public function testCorpus($schemaMap = true): void } /** - * Prose test: Custom Endpoint + * Prose test 7: Custom Endpoint * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#custom-endpoint-test * @dataProvider customEndpointProvider */ public function testCustomEndpoint(Closure $test): void @@ -811,7 +818,9 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio } /** - * Prose test: Bypass spawning mongocryptd (via mongocryptdBypassSpawn) + * Prose test 8: Bypass Spawning mongocryptd (via mongocryptdBypassSpawn) + * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#via-mongocryptdbypassspawn */ public function testBypassSpawningMongocryptdViaBypassSpawn(): void { @@ -844,7 +853,9 @@ public function testBypassSpawningMongocryptdViaBypassSpawn(): void } /** - * Bypass spawning mongocryptd (via bypassAutoEncryption) + * Prose test 8: Bypass spawning mongocryptd (via bypassAutoEncryption) + * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#via-bypassautoencryption */ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void { @@ -870,7 +881,7 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void } /** - * Prose test: Invalid KMS Certificate + * Prose test 10: KMS TLS Tests (Invalid KMS Certificate) * * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#invalid-kms-certificate */ @@ -898,7 +909,7 @@ public function testInvalidKmsCertificate(): void } /** - * Prose test: Invalid Hostname in KMS Certificate + * Prose test 10: KMS TLS Tests (Invalid Hostname in KMS Certificate) * * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#invalid-hostname-in-kms-certificate */ @@ -926,7 +937,7 @@ public function testInvalidHostnameInKmsCertificate(): void } /** - * Prose test: KMS TLS Options + * Prose test 11: KMS TLS Options * * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#kms-tls-options-tests * @dataProvider provideKmsTlsOptionsTests From ee660a0d45bb3348138f834aced5f2bcc73f6249 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 25 May 2022 14:52:00 -0400 Subject: [PATCH 156/321] Revise Int64 helper method and apply type hinting --- .../ClientSideEncryptionSpecTest.php | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 81989733e..59cf084e0 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -1154,27 +1154,10 @@ static function (self $test, ClientEncryption $clientEncryptionNoClientCert, Cli ]; } - /** - * Casts the value for a BSON corpus structure to int64 if necessary. - * - * This is a workaround for an issue in mongocryptd which refuses to encrypt - * int32 values if the schemaMap defines a "long" bsonType for an object. - * - * @param object $data - * - * @return Int64|mixed - */ - private function craftInt64($data) + private function createInt64(string $value): Int64 { - if ($data->type !== 'long' || $data->value instanceof Int64) { - return $data->value; - } - - $class = Int64::class; - - $intAsString = sprintf((string) $data->value); - $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($intAsString), $intAsString); - $int64 = sprintf('C:%d:"%s":%d:{%s}', strlen($class), $class, strlen($array), $array); + $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value); + $int64 = sprintf('C:%d:"%s":%d:{%s}', strlen(Int64::class), Int64::class, strlen($array), $array); return unserialize($int64); } @@ -1233,7 +1216,13 @@ private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEnc if ($data->allowed) { try { - $encrypted = $clientEncryption->encrypt($this->craftInt64($data), $encryptionOptions); + /* Note: workaround issue where mongocryptd refuses to encrypt + * 32-bit integers if schemaMap defines a "long" BSON type. */ + $value = $data->type === 'long' && ! $data->value instanceof Int64 + ? $this->createInt64($data->value) + : $data->value; + + $encrypted = $clientEncryption->encrypt($value, $encryptionOptions); } catch (EncryptionException $e) { $this->fail('Could not encrypt value for field ' . $fieldName . ': ' . $e->getMessage()); } @@ -1279,7 +1268,11 @@ private function insertKeyVaultData(?array $keyVaultData = null): void private function prepareCorpusData(string $fieldName, stdClass $data, ClientEncryption $clientEncryption) { if ($data->method === 'auto') { - $data->value = $this->craftInt64($data); + /* Note: workaround issue where mongocryptd refuses to encrypt + * 32-bit integers if schemaMap defines a "long" BSON type. */ + if ($data->type === 'long' && ! $data->value instanceof Int64) { + $data->value = $this->createInt64($data->value); + } return $data; } From 200d44349ff76f25f12d2b643690117e8e24f8da Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 31 May 2022 10:38:02 -0400 Subject: [PATCH 157/321] PHPLIB-851: Queryable encryption support for create/drop collection helpers --- ...-MongoDBCollection-method-drop-option.yaml | 12 +++-- ...tabase-method-createCollection-option.yaml | 18 +++++++ ...Database-method-dropCollection-option.yaml | 6 +++ .../apiargs-dropCollection-option.yaml | 15 ++++++ src/Collection.php | 15 ++++++ src/Database.php | 39 ++++++++++++++- src/Operation/CreateCollection.php | 8 +++- src/functions.php | 48 +++++++++++++++++++ tests/Operation/CreateCollectionTest.php | 4 ++ 9 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 docs/includes/apiargs-dropCollection-option.yaml diff --git a/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml index 3a66ad3b9..7e08cf431 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml @@ -1,8 +1,8 @@ source: - file: apiargs-MongoDBCollection-common-option.yaml - ref: typeMap + file: apiargs-dropCollection-option.yaml + ref: encryptedFields post: | - This will be used for the returned command result document. + .. versionadded:: 1.13 --- source: file: apiargs-common-option.yaml @@ -10,6 +10,12 @@ source: post: | .. versionadded:: 1.3 --- +source: + file: apiargs-MongoDBCollection-common-option.yaml + ref: typeMap +post: | + This will be used for the returned command result document. +--- source: file: apiargs-MongoDBCollection-common-option.yaml ref: writeConcern diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 10d9252b3..82865dc16 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -68,6 +68,24 @@ pre: | ` for the collection. --- arg_name: option +name: encryptedFields +type: document +description: | + A document describing encrypted fields for queryable encryption. If omitted, + the ``encryptedFieldsMap`` option within the ``autoEncryption`` driver option + will be consulted. See the + `Client Side Encryption specification `_ + for more information. + + This option is available in MongoDB 6.0+ and will result in an exception at + execution time if specified for an older server version. + + .. versionadded:: 1.13 +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: expireAfterSeconds type: integer description: | diff --git a/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml index 5b3c18c33..f08f9e060 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml @@ -1,3 +1,9 @@ +source: + file: apiargs-dropCollection-option.yaml + ref: encryptedFields +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-dropCollection-option.yaml b/docs/includes/apiargs-dropCollection-option.yaml new file mode 100644 index 000000000..018effa9e --- /dev/null +++ b/docs/includes/apiargs-dropCollection-option.yaml @@ -0,0 +1,15 @@ +arg_name: option +name: encryptedFields +type: array|object +description: | + A document describing encrypted fields for queryable encryption. If omitted, + the ``encryptedFieldsMap`` option within the ``autoEncryption`` driver option + will be consulted. If ``encryptedFieldsMap`` was defined but does not specify + this collection, the library will make a final attempt to consult the + server-side value for ``encryptedFields``. See the + `Client Side Encryption specification `_ + for more information. +interface: phpmethod +operation: ~ +optional: true +... diff --git a/src/Collection.php b/src/Collection.php index df53fb709..bc864256c 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -495,6 +495,21 @@ public function drop(array $options = []) $options['writeConcern'] = $this->writeConcern; } + $encryptedFields = $options['encryptedFields'] + ?? get_encrypted_fields_from_driver($this->databaseName, $this->collectionName, $this->manager) + ?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $this->manager, $server) + ?? null; + + if ($encryptedFields !== null) { + // encryptedFields is not passed to the drop command + unset($options['encryptedFields']); + + $encryptedFields = (array) $encryptedFields; + (new DropCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $this->collectionName . '.esc'))->execute($server); + (new DropCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecc'))->execute($server); + (new DropCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecoc'))->execute($server); + } + $operation = new DropCollection($this->databaseName, $this->collectionName, $options); return $operation->execute($server); diff --git a/src/Database.php b/src/Database.php index 72e44e507..4d8a74463 100644 --- a/src/Database.php +++ b/src/Database.php @@ -33,6 +33,7 @@ use MongoDB\Model\CollectionInfoIterator; use MongoDB\Operation\Aggregate; use MongoDB\Operation\CreateCollection; +use MongoDB\Operation\CreateIndexes; use MongoDB\Operation\DatabaseCommand; use MongoDB\Operation\DropCollection; use MongoDB\Operation\DropDatabase; @@ -275,9 +276,30 @@ public function createCollection($collectionName, array $options = []) $options['writeConcern'] = $this->writeConcern; } + $encryptedFields = $options['encryptedFields'] + ?? get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager) + ?? null; + + if ($encryptedFields !== null) { + // encryptedFields is passed to the create command + $options['encryptedFields'] = $encryptedFields; + + $encryptedFields = (array) $encryptedFields; + $enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]]; + (new CreateCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc', $enxcolOptions))->execute($server); + (new CreateCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc', $enxcolOptions))->execute($server); + (new CreateCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc', $enxcolOptions))->execute($server); + } + $operation = new CreateCollection($this->databaseName, $collectionName, $options); - return $operation->execute($server); + $result = $operation->execute($server); + + if ($encryptedFields !== null) { + (new CreateIndexes($this->databaseName, $collectionName, [['key' => ['__safeContent__' => 1]]]))->execute($server); + } + + return $result; } /** @@ -330,6 +352,21 @@ public function dropCollection($collectionName, array $options = []) $options['writeConcern'] = $this->writeConcern; } + $encryptedFields = $options['encryptedFields'] + ?? get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager) + ?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $this->manager, $server) + ?? null; + + if ($encryptedFields !== null) { + // encryptedFields is not passed to the drop command + unset($options['encryptedFields']); + + $encryptedFields = (array) $encryptedFields; + (new DropCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'))->execute($server); + (new DropCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'))->execute($server); + (new DropCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'))->execute($server); + } + $operation = new DropCollection($this->databaseName, $collectionName, $options); return $operation->execute($server); diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index 3b748cf61..5e0d54d22 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -83,6 +83,8 @@ class CreateCollection implements Executable * * * collation (document): Collation specification. * + * * encryptedFields (document): CSFLE specification. + * * * expireAfterSeconds: The TTL for documents in time series collections. * * This is not supported for servers versions < 5.0. @@ -158,6 +160,10 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); } + if (isset($options['encryptedFields']) && ! is_array($options['encryptedFields']) && ! is_object($options['encryptedFields'])) { + throw InvalidArgumentException::invalidType('"encryptedFields" option', $options['encryptedFields'], 'array or object'); + } + if (isset($options['expireAfterSeconds']) && ! is_integer($options['expireAfterSeconds'])) { throw InvalidArgumentException::invalidType('"expireAfterSeconds" option', $options['expireAfterSeconds'], 'integer'); } @@ -285,7 +291,7 @@ private function createCommand() } } - foreach (['changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { + foreach (['changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'encryptedFields', 'indexOptionDefaults', 'storageEngine', 'timeseries', 'validator'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = (object) $this->options[$option]; } diff --git a/src/functions.php b/src/functions.php index 37b2edc6d..c0ab80e9a 100644 --- a/src/functions.php +++ b/src/functions.php @@ -27,6 +27,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\RuntimeException; +use MongoDB\Operation\ListCollections; use MongoDB\Operation\WithTransaction; use ReflectionClass; use ReflectionException; @@ -123,6 +124,53 @@ function generate_index_name($document): string return $name; } +/** + * Return a collection's encryptedFields from the encryptedFieldsMap + * autoEncryption driver option (if available). + * + * @internal + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#drop-collection-helper + * @see Collection::drop + * @see Database::createCollection + * @see Database::dropCollection + * @return array|object|null + */ +function get_encrypted_fields_from_driver(string $databaseName, string $collectionName, Manager $manager) +{ + $encryptedFieldsMap = (array) $manager->getEncryptedFieldsMap(); + + return $encryptedFieldsMap[$databaseName . '.' . $collectionName] ?? null; +} + +/** + * Return a collection's encryptedFields option from the server (if any). + * + * @internal + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#drop-collection-helper + * @see Collection::drop + * @see Database::dropCollection + * @return array|object|null + */ +function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Manager $manager, Server $server) +{ + // No-op if the encryptedFieldsMap autoEncryption driver option was omitted + if ($manager->getEncryptedFieldsMap() === null) { + return null; + } + + $collectionInfoIterator = (new ListCollections($databaseName, ['filter' => ['name' => $collectionName]]))->execute($server); + + foreach ($collectionInfoIterator as $collectionInfo) { + /* Note: ListCollections applies a typeMap that converts BSON documents + * to PHP arrays. This should not be problematic as encryptedFields here + * is only used by drop helpers to obtain names of supporting encryption + * collections. */ + return $collectionInfo['options']['encryptedFields'] ?? null; + } + + return null; +} + /** * Return whether the first key in the document starts with a "$" character. * diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php index ec6205fca..64b2f35db 100644 --- a/tests/Operation/CreateCollectionTest.php +++ b/tests/Operation/CreateCollectionTest.php @@ -47,6 +47,10 @@ public function provideInvalidConstructorOptions() $options[][] = ['collation' => $value]; } + foreach ($this->getInvalidDocumentValues() as $value) { + $options[][] = ['encryptedFields' => $value]; + } + foreach ($this->getInvalidIntegerValues() as $value) { $options[][] = ['expireAfterSeconds' => $value]; } From 1d7d5d5c4b82013f35af2362ccc17fcd0cdc7740 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 31 May 2022 15:02:14 -0400 Subject: [PATCH 158/321] PHPLIB-885: Explicit encryption prose tests --- tests/FunctionalTestCase.php | 5 + .../ClientSideEncryptionSpecTest.php | 195 ++++++++++++++++++ .../etc/data/encryptedFields.json | 33 +++ .../etc/data/keys/key1-document.json | 30 +++ .../etc/data/keys/key1-id.json | 6 + .../etc/data/keys/key2-document.json | 30 +++ .../etc/data/keys/key2-id.json | 6 + 7 files changed, 305 insertions(+) create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json create mode 100644 tests/SpecTests/client-side-encryption/etc/data/keys/key1-document.json create mode 100644 tests/SpecTests/client-side-encryption/etc/data/keys/key1-id.json create mode 100644 tests/SpecTests/client-side-encryption/etc/data/keys/key2-document.json create mode 100644 tests/SpecTests/client-side-encryption/etc/data/keys/key2-id.json diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index b81cd3241..c97474cee 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -391,6 +391,11 @@ protected function isMongos() return $this->getPrimaryServer()->getType() == Server::TYPE_MONGOS; } + protected function isStandalone() + { + return $this->getPrimaryServer()->getType() == Server::TYPE_STANDALONE; + } + /** * Return whether serverless (i.e. proxy as mongos) is being utilized. */ diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 59cf084e0..29df4447a 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -5,6 +5,7 @@ use Closure; use MongoDB\BSON\Binary; use MongoDB\BSON\Int64; +use MongoDB\Client; use MongoDB\Collection; use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Exception\AuthenticationException; @@ -24,6 +25,7 @@ use function base64_decode; use function basename; +use function count; use function explode; use function file_get_contents; use function getenv; @@ -36,6 +38,7 @@ use function str_repeat; use function strlen; use function unserialize; +use function version_compare; use const DIRECTORY_SEPARATOR; use const PATH_SEPARATOR; @@ -1154,6 +1157,183 @@ static function (self $test, ClientEncryption $clientEncryptionNoClientCert, Cli ]; } + /** + * Prose test 12: Explicit Encryption + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#explicit-encryption + * @dataProvider provideExplicitEncryptionTests + */ + public function testExplicitEncryption(Closure $test): void + { + if ($this->isStandalone() || ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets())) { + $this->markTestSkipped('Explicit encryption tests require replica sets'); + } + + if (version_compare($this->getServerVersion(), '6.0.0', '<')) { + $this->markTestSkipped('Explicit encryption tests require MongoDB 6.0 or later'); + } + + // Test setup + $encryptedFields = $this->prepareEncryptedFields($this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/encryptedFields.json'))); + $key1Document = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/keys/key1-document.json')); + $key1Id = $key1Document->_id; + + $client = static::createTestClient(); + + $database = $client->selectDatabase('db'); + $database->dropCollection('explicit_encryption', ['encryptedFields' => $encryptedFields]); + $database->createCollection('explicit_encryption', ['encryptedFields' => $encryptedFields]); + + $database = $client->selectDatabase('keyvault'); + $database->dropCollection('datakeys'); + $database->createCollection('datakeys'); + + $client->selectCollection('keyvault', 'datakeys')->insertOne($key1Document, ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]); + + $keyVaultClient = static::createTestClient(); + + $clientEncryption = new ClientEncryption([ + 'keyVaultClient' => $keyVaultClient->getManager(), + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]], + ]); + + $autoEncryptionOpts = [ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]], + 'bypassQueryAnalysis' => true, + ]; + + $encryptedClient = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); + + $test($this, $clientEncryption, $encryptedClient, $keyVaultClient, $key1Id); + } + + public static function provideExplicitEncryptionTests() + { + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-1-can-insert-encrypted-indexed-and-find + yield 'Case 1: can insert encrypted indexed and find' => [ + static function (self $test, ClientEncryption $clientEncryption, Client $encryptedClient, Client $keyVaultClient, Binary $key1Id): void { + $value = 'encrypted indexed value'; + + $insertPayload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + ]); + + $collection = $encryptedClient->selectCollection('db', 'explicit_encryption'); + $collection->insertOne(['encryptedIndexed' => $insertPayload]); + + $findPayload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + 'queryType' => ClientEncryption::QUERY_TYPE_EQUALITY, + ]); + + $results = $collection->find(['encryptedIndexed' => $findPayload])->toArray(); + + $test->assertCount(1, $results); + $test->assertSame($value, $results[0]['encryptedIndexed']); + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-2-can-insert-encrypted-indexed-and-find-with-non-zero-contention + yield 'Case 2: can insert encrypted indexed and find with non-zero contention' => [ + static function (self $test, ClientEncryption $clientEncryption, Client $encryptedClient, Client $keyVaultClient, Binary $key1Id): void { + $value = 'encrypted indexed value'; + + $collection = $encryptedClient->selectCollection('db', 'explicit_encryption'); + + for ($i = 0; $i < 10; $i++) { + $insertPayload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + 'contentionFactor' => 10, + ]); + + $collection->insertOne(['encryptedIndexed' => $insertPayload]); + } + + $findPayload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + 'queryType' => ClientEncryption::QUERY_TYPE_EQUALITY, + ]); + + $results = $collection->find(['encryptedIndexed' => $findPayload])->toArray(); + + $test->assertLessThan(10, count($results)); + + foreach ($results as $result) { + $test->assertSame($value, $result['encryptedIndexed']); + } + + $findPayload2 = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + 'queryType' => ClientEncryption::QUERY_TYPE_EQUALITY, + 'contentionFactor' => 10, + ]); + + $results = $collection->find(['encryptedIndexed' => $findPayload2])->toArray(); + + $test->assertCount(10, $results); + + foreach ($results as $result) { + $test->assertSame($value, $result['encryptedIndexed']); + } + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-3-can-insert-encrypted-unindexed + yield 'Case 3: can insert encrypted unindexed' => [ + static function (self $test, ClientEncryption $clientEncryption, Client $encryptedClient, Client $keyVaultClient, Binary $key1Id): void { + $value = 'encrypted unindexed value'; + + $insertPayload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_UNINDEXED, + ]); + + $collection = $encryptedClient->selectCollection('db', 'explicit_encryption'); + $collection->insertOne(['_id' => 1, 'encryptedUnindexed' => $insertPayload]); + + $results = $collection->find(['_id' => 1])->toArray(); + + $test->assertCount(1, $results); + $test->assertSame($value, $results[0]['encryptedUnindexed']); + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-4-can-roundtrip-encrypted-indexed + yield 'Case 4: can roundtrip encrypted indexed' => [ + static function (self $test, ClientEncryption $clientEncryption, Client $encryptedClient, Client $keyVaultClient, Binary $key1Id): void { + $value = 'encrypted indexed value'; + + $payload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + ]); + + $test->assertSame($value, $clientEncryption->decrypt($payload)); + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-5-can-roundtrip-encrypted-unindexed + yield 'Case 5: can roundtrip encrypted unindexed' => [ + static function (self $test, ClientEncryption $clientEncryption, Client $encryptedClient, Client $keyVaultClient, Binary $key1Id): void { + $value = 'encrypted unindexed value'; + + $payload = $clientEncryption->encrypt($value, [ + 'keyId' => $key1Id, + 'algorithm' => ClientEncryption::ALGORITHM_UNINDEXED, + ]); + + $test->assertSame($value, $clientEncryption->decrypt($payload)); + }, + ]; + } + private function createInt64(string $value): Int64 { $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value); @@ -1283,6 +1463,21 @@ private function prepareCorpusData(string $fieldName, stdClass $data, ClientEncr return $data->allowed ? $returnData : $data; } + /** + * @todo Remove this once SERVER-66901 is implemented + * @see https://jira.mongodb.org/browse/PHPLIB-884 + */ + private function prepareEncryptedFields(stdClass $encryptedFields): stdClass + { + foreach ($encryptedFields->fields as $field) { + if (isset($field->queries->contention)) { + $field->queries->contention = $this->createInt64($field->queries->contention); + } + } + + return $encryptedFields; + } + private function skipIfLocalMongocryptdIsUnavailable(): void { $paths = explode(PATH_SEPARATOR, getenv("PATH")); diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json new file mode 100644 index 000000000..2364590e4 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json @@ -0,0 +1,33 @@ +{ + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/etc/data/keys/key1-document.json b/tests/SpecTests/client-side-encryption/etc/data/keys/key1-document.json new file mode 100644 index 000000000..566b56c35 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/etc/data/keys/key1-document.json @@ -0,0 +1,30 @@ +{ + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } +} diff --git a/tests/SpecTests/client-side-encryption/etc/data/keys/key1-id.json b/tests/SpecTests/client-side-encryption/etc/data/keys/key1-id.json new file mode 100644 index 000000000..7d18f52eb --- /dev/null +++ b/tests/SpecTests/client-side-encryption/etc/data/keys/key1-id.json @@ -0,0 +1,6 @@ +{ + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } +} diff --git a/tests/SpecTests/client-side-encryption/etc/data/keys/key2-document.json b/tests/SpecTests/client-side-encryption/etc/data/keys/key2-document.json new file mode 100644 index 000000000..a654d980b --- /dev/null +++ b/tests/SpecTests/client-side-encryption/etc/data/keys/key2-document.json @@ -0,0 +1,30 @@ +{ + "_id": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } +} diff --git a/tests/SpecTests/client-side-encryption/etc/data/keys/key2-id.json b/tests/SpecTests/client-side-encryption/etc/data/keys/key2-id.json new file mode 100644 index 000000000..6e9b87bbc --- /dev/null +++ b/tests/SpecTests/client-side-encryption/etc/data/keys/key2-id.json @@ -0,0 +1,6 @@ +{ + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } +} From b1ffe890ea18dc4c391823b4cebae73d79a25931 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 1 Jun 2022 14:35:16 -0400 Subject: [PATCH 159/321] PHPLIB-888: Use a dedicated clients for legacy spec tests While some specs already required separate clients (e.g. transactions for txnNumber assertions), applying it generally will allow internal operations (e.g. assertCollectionExists) to use separate clients and also allow command monitoring to focus on actual test operations. This also refactors ClientSideEncryptionSpecTest::insertKeyVaultData and several CSFLE prose tests, since a client and its key vault client must share the disableClientPersistence driver option. --- tests/SpecTests/AtlasDataLakeSpecTest.php | 2 +- .../ClientSideEncryptionSpecTest.php | 54 ++++++++----------- tests/SpecTests/CommandExpectations.php | 34 ++++++------ tests/SpecTests/Context.php | 42 +++++++++------ tests/SpecTests/Operation.php | 6 +-- tests/SpecTests/ReadWriteConcernSpecTest.php | 2 +- tests/SpecTests/RetryableReadsSpecTest.php | 2 +- tests/SpecTests/TransactionsSpecTest.php | 2 +- 8 files changed, 73 insertions(+), 71 deletions(-) diff --git a/tests/SpecTests/AtlasDataLakeSpecTest.php b/tests/SpecTests/AtlasDataLakeSpecTest.php index 897a7332d..4b37a2f12 100644 --- a/tests/SpecTests/AtlasDataLakeSpecTest.php +++ b/tests/SpecTests/AtlasDataLakeSpecTest.php @@ -83,7 +83,7 @@ public function testAtlasDataLake(stdClass $test, ?array $runOn, array $data, ?s } if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromCrud((array) $test->expectations); + $commandExpectations = CommandExpectations::fromCrud($context->getClient(), (array) $test->expectations); $commandExpectations->startMonitoring(); } diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 29df4447a..c568623e5 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -115,7 +115,7 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d $this->setContext($context); - $this->insertKeyVaultData($keyVaultData); + self::insertKeyVaultData($context->getClient(), $keyVaultData); $this->dropTestAndOutcomeCollections(); $this->createTestCollection($jsonSchema); $this->insertDataFixtures($data); @@ -127,7 +127,7 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d $context->enableEncryption(); if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromClientSideEncryption($test->expectations); + $commandExpectations = CommandExpectations::fromClientSideEncryption($context->getClient(), $test->expectations); $commandExpectations->startMonitoring(); } @@ -192,14 +192,12 @@ public function provideTests() */ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey): void { - $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); - $client = $this->getContext()->getClient(); - - // This empty call ensures that the key vault is dropped with a majority - // write concern - $this->insertKeyVaultData([]); + $client = static::createTestClient(); $client->selectCollection('db', 'coll')->drop(); + // Ensure that the key vault is dropped with a majority write concern + self::insertKeyVaultData($client, []); + $encryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ @@ -332,19 +330,12 @@ public static function dataKeyProvider() */ public function testExternalKeyVault($withExternalKeyVault): void { - $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); - $client = $this->getContext()->getClient(); + $client = static::createTestClient(); $client->selectCollection('db', 'coll')->drop(); - $keyVaultCollection = $client->selectCollection( - 'keyvault', - 'datakeys', - ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $this->getContext()->defaultWriteOptions - ); - $keyVaultCollection->drop(); - $keyId = $keyVaultCollection - ->insertOne($this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-key.json'))) - ->getInsertedId(); + self::insertKeyVaultData($client, [ + $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-key.json')), + ]); $encryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', @@ -386,7 +377,10 @@ public function testExternalKeyVault($withExternalKeyVault): void $this->expectException(AuthenticationException::class); } - $clientEncryption->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + $clientEncryption->encrypt('test', [ + 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, + 'keyId' => new Binary(base64_decode('LOCALAAAAAAAAAAAAAAAAA=='), Binary::TYPE_UUID), + ]); } public static function provideBSONSizeLimitsAndBatchSplittingTests() @@ -483,13 +477,12 @@ static function (self $test, Collection $collection, array $document): void { */ public function testBSONSizeLimitsAndBatchSplitting(Closure $test): void { - $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); - $client = $this->getContext()->getClient(); + $client = static::createTestClient(); $client->selectCollection('db', 'coll')->drop(); $client->selectDatabase('db')->createCollection('coll', ['validator' => ['$jsonSchema' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-schema.json'))]]); - $this->insertKeyVaultData([ + self::insertKeyVaultData($client, [ $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-key.json')), ]); @@ -551,20 +544,16 @@ public function testViewsAreProhibited(): void */ public function testCorpus($schemaMap = true): void { - $this->setContext(Context::fromClientSideEncryption((object) [], 'db', 'coll')); - $client = $this->getContext()->getClient(); - + $client = static::createTestClient(); $client->selectDatabase('db')->dropCollection('coll'); $schema = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-schema.json')); if (! $schemaMap) { - $client - ->selectDatabase('db') - ->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); + $client->selectDatabase('db')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]); } - $this->insertKeyVaultData([ + self::insertKeyVaultData($client, [ $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-local.json')), $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-aws.json')), $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-azure.json')), @@ -1432,10 +1421,9 @@ private static function getEnv(string $name): string return $value; } - private function insertKeyVaultData(?array $keyVaultData = null): void + private static function insertKeyVaultData(Client $client, ?array $keyVaultData = null): void { - $context = $this->getContext(); - $collection = $context->selectCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)] + $context->defaultWriteOptions); + $collection = $client->selectCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]); $collection->drop(); if (empty($keyVaultData)) { diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index d5b3e2a76..e25ea7c29 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -4,6 +4,7 @@ use ArrayIterator; use LogicException; +use MongoDB\Client; use MongoDB\Driver\Monitoring\CommandFailedEvent; use MongoDB\Driver\Monitoring\CommandStartedEvent; use MongoDB\Driver\Monitoring\CommandSubscriber; @@ -13,8 +14,6 @@ use function count; use function in_array; use function key; -use function MongoDB\Driver\Monitoring\addSubscriber; -use function MongoDB\Driver\Monitoring\removeSubscriber; /** * Spec test CommandStartedEvent expectations. @@ -45,8 +44,13 @@ class CommandExpectations implements CommandSubscriber /** @var string[] */ private $ignoredCommandNames = []; - private function __construct(array $events) + /** @var Client */ + private $observedClient; + + private function __construct(Client $observedClient, array $events) { + $this->observedClient = $observedClient; + foreach ($events as $event) { switch (key((array) $event)) { case 'command_failed_event': @@ -70,9 +74,9 @@ private function __construct(array $events) } } - public static function fromClientSideEncryption(array $expectedEvents) + public static function fromClientSideEncryption(Client $client, array $expectedEvents) { - $o = new self($expectedEvents); + $o = new self($client, $expectedEvents); $o->ignoreCommandFailed = true; $o->ignoreCommandSucceeded = true; @@ -81,9 +85,9 @@ public static function fromClientSideEncryption(array $expectedEvents) return $o; } - public static function fromCrud(array $expectedEvents) + public static function fromCrud(Client $client, array $expectedEvents) { - $o = new self($expectedEvents); + $o = new self($client, $expectedEvents); $o->ignoreCommandFailed = true; $o->ignoreCommandSucceeded = true; @@ -91,9 +95,9 @@ public static function fromCrud(array $expectedEvents) return $o; } - public static function fromReadWriteConcern(array $expectedEvents) + public static function fromReadWriteConcern(Client $client, array $expectedEvents) { - $o = new self($expectedEvents); + $o = new self($client, $expectedEvents); $o->ignoreCommandFailed = true; $o->ignoreCommandSucceeded = true; @@ -101,9 +105,9 @@ public static function fromReadWriteConcern(array $expectedEvents) return $o; } - public static function fromRetryableReads(array $expectedEvents) + public static function fromRetryableReads(Client $client, array $expectedEvents) { - $o = new self($expectedEvents); + $o = new self($client, $expectedEvents); $o->ignoreCommandFailed = true; $o->ignoreCommandSucceeded = true; @@ -116,9 +120,9 @@ public static function fromRetryableReads(array $expectedEvents) return $o; } - public static function fromTransactions(array $expectedEvents) + public static function fromTransactions(Client $client, array $expectedEvents) { - $o = new self($expectedEvents); + $o = new self($client, $expectedEvents); $o->ignoreCommandFailed = true; $o->ignoreCommandSucceeded = true; @@ -181,7 +185,7 @@ public function commandSucceeded(CommandSucceededEvent $event): void */ public function startMonitoring(): void { - addSubscriber($this); + $this->observedClient->getManager()->addSubscriber($this); } /** @@ -189,7 +193,7 @@ public function startMonitoring(): void */ public function stopMonitoring(): void { - removeSubscriber($this); + $this->observedClient->getManager()->removeSubscriber($this); } /** diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 1521bd78e..a2c277404 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -15,7 +15,6 @@ use function array_keys; use function getenv; use function implode; -use function uniqid; /** * Execution context for spec tests. @@ -58,6 +57,9 @@ final class Context /** @var object */ public $session1Lsid; + /** @var Client */ + private $internalClient; + /** @var Client|null */ private $encryptedClient; @@ -69,6 +71,7 @@ private function __construct(string $databaseName, ?string $collectionName) $this->databaseName = $databaseName; $this->collectionName = $collectionName; $this->outcomeCollectionName = $collectionName; + $this->internalClient = FunctionalTestCase::createTestClient(); } public function disableEncryption(): void @@ -100,11 +103,6 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - /* mongocryptd caches collection information, which causes test failures - * if we reuse the client. Thus, we add a random value to ensure we're - * creating a new client for each test. */ - $driverOptions = ['random' => uniqid()]; - $autoEncryptionOptions = []; if (isset($clientOptions['autoEncryptOpts'])) { @@ -138,10 +136,10 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ $o->outcomeCollectionName = $test->outcome->collection->name; } - $o->client = FunctionalTestCase::createTestClient(null, $clientOptions, $driverOptions); + $o->client = self::createTestClient(null, $clientOptions); if ($autoEncryptionOptions !== []) { - $o->encryptedClient = FunctionalTestCase::createTestClient(null, $clientOptions, $driverOptions + ['autoEncryption' => $autoEncryptionOptions]); + $o->encryptedClient = self::createTestClient(null, $clientOptions, ['autoEncryption' => $autoEncryptionOptions]); } return $o; @@ -175,7 +173,7 @@ public static function fromCrud(stdClass $test, $databaseName, $collectionName) 'readPreference' => new ReadPreference('primary'), ]; - $o->client = FunctionalTestCase::createTestClient(null, $clientOptions); + $o->client = self::createTestClient(null, $clientOptions); return $o; } @@ -190,7 +188,7 @@ public static function fromReadWriteConcern(stdClass $test, $databaseName, $coll $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - $o->client = FunctionalTestCase::createTestClient(null, $clientOptions); + $o->client = self::createTestClient(null, $clientOptions); return $o; } @@ -203,7 +201,7 @@ public static function fromRetryableReads(stdClass $test, $databaseName, $collec $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - $o->client = FunctionalTestCase::createTestClient(null, $clientOptions); + $o->client = self::createTestClient(null, $clientOptions); return $o; } @@ -218,7 +216,7 @@ public static function fromRetryableWrites(stdClass $test, $databaseName, $colle $o->outcomeCollectionName = $test->outcome->collection->name; } - $o->client = FunctionalTestCase::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); + $o->client = self::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); return $o; } @@ -238,10 +236,7 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : []; - // Transaction spec tests expect a new client for each test so that txnNumber values are deterministic. - $driverOptions = ['disableClientPersistence' => true]; - - $o->client = FunctionalTestCase::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions, $driverOptions); + $o->client = self::createTestClient(FunctionalTestCase::getUri($useMultipleMongoses), $clientOptions); $session0Options = isset($test->sessionOptions->session0) ? (array) $test->sessionOptions->session0 : []; $session1Options = isset($test->sessionOptions->session1) ? (array) $test->sessionOptions->session1 : []; @@ -338,6 +333,11 @@ public function getGridFSBucket(array $bucketOptions = []) return $this->selectGridFSBucket($this->databaseName, $this->bucketName, $bucketOptions); } + public function getInternalClient(): Client + { + return $this->internalClient; + } + /** * Prepare options readConcern, readPreference, and writeConcern options by * creating value objects. @@ -470,6 +470,16 @@ public function selectGridFSBucket($databaseName, $bucketName, array $bucketOpti return $this->selectDatabase($databaseName)->selectGridFSBucket($this->prepareGridFSBucketOptions($bucketOptions, $bucketName)); } + private static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client + { + /* Default to using a dedicated client. This was already necessary for + * CSFLE and Transaction spec tests, but is generally useful for any + * test that observes command monitoring events. */ + $driverOptions += ['disableClientPersistence' => true]; + + return FunctionalTestCase::createTestClient($uri, $options, $driverOptions); + } + private function prepareGridFSBucketOptions(array $options, $bucketPrefix) { if ($bucketPrefix !== null) { diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index 2eede96f2..8ff103916 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -608,7 +608,7 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context $databaseName = $args['database']; $collectionName = $args['collection']; - $test->assertContains($collectionName, $context->selectDatabase($databaseName)->listCollectionNames()); + $test->assertContains($collectionName, $context->getInternalClient()->selectDatabase($databaseName)->listCollectionNames()); return null; @@ -616,7 +616,7 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context $databaseName = $args['database']; $collectionName = $args['collection']; - $test->assertNotContains($collectionName, $context->selectDatabase($databaseName)->listCollectionNames()); + $test->assertNotContains($collectionName, $context->getInternalClient()->selectDatabase($databaseName)->listCollectionNames()); return null; @@ -679,7 +679,7 @@ private function getIndexNames(Context $context, string $databaseName, string $c function (IndexInfo $indexInfo) { return $indexInfo->getName(); }, - iterator_to_array($context->selectCollection($databaseName, $collectionName)->listIndexes()) + iterator_to_array($context->getInternalClient()->selectCollection($databaseName, $collectionName)->listIndexes()) ); } diff --git a/tests/SpecTests/ReadWriteConcernSpecTest.php b/tests/SpecTests/ReadWriteConcernSpecTest.php index 96a4f7ec6..96560a86a 100644 --- a/tests/SpecTests/ReadWriteConcernSpecTest.php +++ b/tests/SpecTests/ReadWriteConcernSpecTest.php @@ -73,7 +73,7 @@ public function testReadWriteConcern(stdClass $test, ?array $runOn, array $data, } if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromReadWriteConcern($test->expectations); + $commandExpectations = CommandExpectations::fromReadWriteConcern($context->getClient(), $test->expectations); $commandExpectations->startMonitoring(); } diff --git a/tests/SpecTests/RetryableReadsSpecTest.php b/tests/SpecTests/RetryableReadsSpecTest.php index 3c5de4e06..e747124ee 100644 --- a/tests/SpecTests/RetryableReadsSpecTest.php +++ b/tests/SpecTests/RetryableReadsSpecTest.php @@ -92,7 +92,7 @@ public function testRetryableReads(stdClass $test, ?array $runOn, $data, string } if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromRetryableReads($test->expectations); + $commandExpectations = CommandExpectations::fromRetryableReads($context->getClient(), $test->expectations); $commandExpectations->startMonitoring(); } diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 3a33ca30a..4f26e9c3e 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -178,7 +178,7 @@ private function runTransactionTest(stdClass $test, ?array $runOn, array $data, } if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromTransactions($test->expectations); + $commandExpectations = CommandExpectations::fromTransactions($context->getClient(), $test->expectations); $commandExpectations->startMonitoring(); } From 50fe7f3e1d30cc188dba6c2e720a0ffbf6b4179f Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 1 Jun 2022 14:42:15 -0400 Subject: [PATCH 160/321] Remove obsolete Context methods These methods should have been removed in f2cfb9ff118f6e377b5449c7a26f48d4052d4ca7 (PHPLIB-879) and 20e8f917f51d99b8a70137cd1d272c1fb8f42ba9 (PHPLIB-652). --- tests/SpecTests/Context.php | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index a2c277404..077bc2bfc 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -88,15 +88,6 @@ public function enableEncryption(): void $this->useEncryptedClient = true; } - public static function fromChangeStreams(stdClass $test, $databaseName, $collectionName) - { - $o = new self($databaseName, $collectionName); - - $o->client = FunctionalTestCase::createTestClient(); - - return $o; - } - public static function fromClientSideEncryption(stdClass $test, $databaseName, $collectionName) { $o = new self($databaseName, $collectionName); @@ -145,15 +136,6 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ return $o; } - public static function fromCommandMonitoring(stdClass $test, $databaseName, $collectionName) - { - $o = new self($databaseName, $collectionName); - - $o->client = FunctionalTestCase::createTestClient(); - - return $o; - } - public static function fromCrud(stdClass $test, $databaseName, $collectionName) { $o = new self($databaseName, $collectionName); From ff1e3faad7f477084cd6e9cb49396f0807288d00 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 1 Jun 2022 14:41:00 -0400 Subject: [PATCH 161/321] PHPLIB-885: Queryable encryption spec tests Synced with mongodb/specifications@cd34149ca1510ff2ec59e72ea9958c6855df9f3f Change logic to use encryptedClient only when available. Support encrypted_fields in CSFLE spec tests. Updates logic for creating the collection under test and also applies a "majority" write concern for the spec's default write options. Also updates a prose test, which does not need to reference the Context option (mainly for spec tests). Add to assertion count when evaluating ErrorExpectation, which avoids a potential PHPUnit warning for a test performing no assertions when a test consisted of an operation(s) with no explicit error/result expectations. --- .../ClientSideEncryptionSpecTest.php | 51 +- tests/SpecTests/Context.php | 24 +- tests/SpecTests/ErrorExpectation.php | 2 + tests/SpecTests/FunctionalTestCase.php | 4 +- .../tests/create-and-createIndexes.json | 115 + .../tests/fle2-BypassQueryAnalysis.json | 289 +++ .../tests/fle2-Compact.json | 232 ++ .../tests/fle2-CreateCollection.json | 2239 +++++++++++++++++ .../tests/fle2-DecryptExistingData.json | 148 ++ .../tests/fle2-Delete.json | 305 +++ ...EncryptedFields-vs-EncryptedFieldsMap.json | 217 ++ .../fle2-EncryptedFields-vs-jsonSchema.json | 304 +++ .../fle2-EncryptedFieldsMap-defaults.json | 105 + .../tests/fle2-FindOneAndUpdate.json | 602 +++++ .../tests/fle2-InsertFind-Indexed.json | 300 +++ .../tests/fle2-InsertFind-Unindexed.json | 250 ++ .../tests/fle2-MissingKey.json | 118 + .../tests/fle2-NoEncryption.json | 86 + .../tests/fle2-Update.json | 610 +++++ ...e2-validatorAndPartialFieldExpression.json | 520 ++++ .../tests/timeoutMS.json | 200 ++ .../validatorAndPartialFieldExpression.json | 642 +++++ 22 files changed, 7332 insertions(+), 31 deletions(-) create mode 100644 tests/SpecTests/client-side-encryption/tests/create-and-createIndexes.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Compact.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Delete.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Update.json create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json create mode 100644 tests/SpecTests/client-side-encryption/tests/timeoutMS.json create mode 100644 tests/SpecTests/client-side-encryption/tests/validatorAndPartialFieldExpression.json diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index c568623e5..ce5a607e8 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -15,7 +15,6 @@ use MongoDB\Driver\Exception\EncryptionException; use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\WriteConcern; -use MongoDB\Operation\CreateCollection; use MongoDB\Tests\CommandObserver; use PHPUnit\Framework\Assert; use PHPUnit\Framework\SkippedTestError; @@ -57,6 +56,8 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase 'awsTemporary: Insert a document with auto encryption using the AWS provider with temporary credentials' => 'Not yet implemented (PHPC-1751)', 'awsTemporary: Insert with invalid temporary credentials' => 'Not yet implemented (PHPC-1751)', 'azureKMS: Insert a document with auto encryption using Azure KMS provider' => 'RHEL platform is missing Azure root certificate (PHPLIB-619)', + 'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)', + 'timeoutMS: remaining timeoutMS applied to find to get keyvault data' => 'Not yet implemented (PHPC-1760)', ]; public function setUp(): void @@ -90,7 +91,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual * @param string $databaseName Name of database under test * @param string $collectionName Name of collection under test */ - public function testClientSideEncryption(stdClass $test, ?array $runOn, array $data, ?array $keyVaultData = null, $jsonSchema = null, ?string $databaseName = null, ?string $collectionName = null): void + public function testClientSideEncryption(stdClass $test, ?array $runOn, array $data, ?stdClass $encryptedFields = null, ?array $keyVaultData = null, ?stdClass $jsonSchema = null, ?string $databaseName = null, ?string $collectionName = null): void { if (isset(self::$incompleteTests[$this->dataDescription()])) { $this->markTestIncomplete(self::$incompleteTests[$this->dataDescription()]); @@ -107,6 +108,11 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d $databaseName = $databaseName ?? $this->getDatabaseName(); $collectionName = $collectionName ?? $this->getCollectionName(); + // TODO: Remove this once SERVER-66901 is implemented (see: PHPLIB-884) + if (isset($test->clientOptions->autoEncryptOpts->encryptedFieldsMap)) { + $test->clientOptions->autoEncryptOpts->encryptedFieldsMap = $this->prepareEncryptedFieldsMap($test->clientOptions->autoEncryptOpts->encryptedFieldsMap); + } + try { $context = Context::fromClientSideEncryption($test, $databaseName, $collectionName); } catch (SkippedTestError $e) { @@ -116,15 +122,15 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d $this->setContext($context); self::insertKeyVaultData($context->getClient(), $keyVaultData); - $this->dropTestAndOutcomeCollections(); - $this->createTestCollection($jsonSchema); + $this->dropTestAndOutcomeCollections(empty($encryptedFields) ? [] : ['encryptedFields' => $encryptedFields]); + $this->createTestCollection($encryptedFields, $jsonSchema); $this->insertDataFixtures($data); if (isset($test->failPoint)) { $this->configureFailPoint($test->failPoint); } - $context->enableEncryption(); + $context->useEncryptedClientIfConfigured = true; if (isset($test->expectations)) { $commandExpectations = CommandExpectations::fromClientSideEncryption($context->getClient(), $test->expectations); @@ -140,7 +146,7 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d $commandExpectations->assert($this, $context); } - $context->disableEncryption(); + $context->useEncryptedClientIfConfigured = false; if (isset($test->outcome->collection->data)) { $this->assertOutcomeCollectionData($test->outcome->collection->data, ResultExpectation::ASSERT_DOCUMENTS_MATCH); @@ -169,6 +175,7 @@ public function provideTests() $runOn = $json->runOn ?? null; $data = $json->data ?? []; // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps + $encryptedFields = $json->encrypted_fields ?? null; $keyVaultData = $json->key_vault_data ?? null; $jsonSchema = $json->json_schema ?? null; $databaseName = $json->database_name ?? null; @@ -177,7 +184,7 @@ public function provideTests() foreach ($json->tests as $test) { $name = $group . ': ' . $test->description; - $testArgs[$name] = [$test, $runOn, $data, $keyVaultData, $jsonSchema, $databaseName, $collectionName]; + $testArgs[$name] = [$test, $runOn, $data, $encryptedFields, $keyVaultData, $jsonSchema, $databaseName, $collectionName]; } } @@ -1331,11 +1338,20 @@ private function createInt64(string $value): Int64 return unserialize($int64); } - private function createTestCollection($jsonSchema): void + private function createTestCollection(?stdClass $encryptedFields = null, ?stdClass $jsonSchema = null): void { - $options = empty($jsonSchema) ? [] : ['validator' => ['$jsonSchema' => $jsonSchema]]; - $operation = new CreateCollection($this->getContext()->databaseName, $this->getContext()->collectionName, $options); - $operation->execute($this->getPrimaryServer()); + $context = $this->getContext(); + $options = $context->defaultWriteOptions; + + if (! empty($encryptedFields)) { + $options['encryptedFields'] = $this->prepareEncryptedFields($encryptedFields); + } + + if (! empty($jsonSchema)) { + $options['validator'] = ['$jsonSchema' => $jsonSchema]; + } + + $context->getDatabase()->createCollection($context->collectionName, $options); } private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEncryption $clientEncryption) @@ -1466,6 +1482,19 @@ private function prepareEncryptedFields(stdClass $encryptedFields): stdClass return $encryptedFields; } + /** + * @todo Remove this once SERVER-66901 is implemented + * @see https://jira.mongodb.org/browse/PHPLIB-884 + */ + private function prepareEncryptedFieldsMap(stdClass $encryptedFieldsMap): stdClass + { + foreach ($encryptedFieldsMap as $namespace => $encryptedFields) { + $encryptedFieldsMap->{$namespace} = $this->prepareEncryptedFields($encryptedFields); + } + + return $encryptedFieldsMap; + } + private function skipIfLocalMongocryptdIsUnavailable(): void { $paths = explode(PATH_SEPARATOR, getenv("PATH")); diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 077bc2bfc..6f1fc55d7 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -57,15 +57,15 @@ final class Context /** @var object */ public $session1Lsid; + /** @var bool */ + public $useEncryptedClientIfConfigured = false; + /** @var Client */ private $internalClient; /** @var Client|null */ private $encryptedClient; - /** @var bool */ - private $useEncryptedClient = false; - private function __construct(string $databaseName, ?string $collectionName) { $this->databaseName = $databaseName; @@ -74,20 +74,6 @@ private function __construct(string $databaseName, ?string $collectionName) $this->internalClient = FunctionalTestCase::createTestClient(); } - public function disableEncryption(): void - { - $this->useEncryptedClient = false; - } - - public function enableEncryption(): void - { - if (! $this->encryptedClient instanceof Client) { - throw new LogicException('Cannot enable encryption without autoEncryption options'); - } - - $this->useEncryptedClient = true; - } - public static function fromClientSideEncryption(stdClass $test, $databaseName, $collectionName) { $o = new self($databaseName, $collectionName); @@ -127,6 +113,8 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ $o->outcomeCollectionName = $test->outcome->collection->name; } + $o->defaultWriteOptions = ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]; + $o->client = self::createTestClient(null, $clientOptions); if ($autoEncryptionOptions !== []) { @@ -292,7 +280,7 @@ public static function getGCPCredentials(): array public function getClient(): Client { - return $this->useEncryptedClient && $this->encryptedClient ? $this->encryptedClient : $this->client; + return $this->useEncryptedClientIfConfigured && $this->encryptedClient ? $this->encryptedClient : $this->client; } public function getCollection(array $collectionOptions = [], array $databaseOptions = []) diff --git a/tests/SpecTests/ErrorExpectation.php b/tests/SpecTests/ErrorExpectation.php index 07164eba6..55ee97cc1 100644 --- a/tests/SpecTests/ErrorExpectation.php +++ b/tests/SpecTests/ErrorExpectation.php @@ -144,6 +144,8 @@ public function assert(TestCase $test, ?Throwable $actual = null): void $test->fail(sprintf("Operation threw unexpected %s: %s\n%s", get_class($actual), $actual->getMessage(), $actual->getTraceAsString())); } + $test->addToAssertionCount(1); + return; } diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index 8dc12c172..ff2318f2c 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -197,7 +197,7 @@ protected function setContext(Context $context): void /** * Drop the test and outcome collections by dropping them. */ - protected function dropTestAndOutcomeCollections(): void + protected function dropTestAndOutcomeCollections(array $testCollectionDropOptions = []): void { $context = $this->getContext(); @@ -213,7 +213,7 @@ protected function dropTestAndOutcomeCollections(): void $collection = null; if ($context->collectionName !== null) { $collection = $context->getCollection($context->defaultWriteOptions); - $collection->drop(); + $collection->drop($testCollectionDropOptions); } if ($context->outcomeCollectionName !== null) { diff --git a/tests/SpecTests/client-side-encryption/tests/create-and-createIndexes.json b/tests/SpecTests/client-side-encryption/tests/create-and-createIndexes.json new file mode 100644 index 000000000..48638a97c --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/create-and-createIndexes.json @@ -0,0 +1,115 @@ +{ + "runOn": [ + { + "minServerVersion": "4.1.10" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "tests": [ + { + "description": "create is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "unencryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "unencryptedCollection", + "validator": { + "unencrypted_string": "foo" + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "unencryptedCollection" + } + } + ] + }, + { + "description": "createIndexes is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "unencryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "unencryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "createIndexes": "unencryptedCollection", + "indexes": [ + { + "name": "name", + "key": { + "name": 1 + } + } + ] + } + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "unencryptedCollection", + "index": "name" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json b/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json new file mode 100644 index 000000000..629faf189 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json @@ -0,0 +1,289 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + }, + { + "_id": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "BypassQueryAnalysis decrypts", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "bypassQueryAnalysis": true + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": { + "$binary": { + "base64": "BHEBAAAFZAAgAAAAAHb62aV7+mqmaGcotPLdG3KP7S8diFwWMLM/5rYtqLrEBXMAIAAAAAAVJ6OWHRv3OtCozHpt3ZzfBhaxZirLv3B+G8PuaaO4EgVjACAAAAAAsZXWOWA+UiCBbrJNB6bHflB/cn7pWSvwWN2jw4FPeIUFcABQAAAAAMdD1nV2nqeI1eXEQNskDflCy8I7/HvvqDKJ6XxjhrPQWdLqjz+8GosGUsB7A8ee/uG9/guENuL25XD+Fxxkv1LLXtavHOlLF7iW0u9yabqqBXUAEAAAAAQSNFZ4EjSYdhI0EjRWeJASEHQAAgAAAAV2AE0AAAAAq83vqxI0mHYSNBI0VniQEkzZZBBDgeZh+h+gXEmOrSFtVvkUcnHWj/rfPW7iJ0G3UJ8zpuBmUM/VjOMJCY4+eDqdTiPIwX+/vNXegc8FZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsAA==", + "subType": "06" + } + } + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encryptedIndexed": "value123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$binary": { + "base64": "BHEBAAAFZAAgAAAAAHb62aV7+mqmaGcotPLdG3KP7S8diFwWMLM/5rYtqLrEBXMAIAAAAAAVJ6OWHRv3OtCozHpt3ZzfBhaxZirLv3B+G8PuaaO4EgVjACAAAAAAsZXWOWA+UiCBbrJNB6bHflB/cn7pWSvwWN2jw4FPeIUFcABQAAAAAMdD1nV2nqeI1eXEQNskDflCy8I7/HvvqDKJ6XxjhrPQWdLqjz+8GosGUsB7A8ee/uG9/guENuL25XD+Fxxkv1LLXtavHOlLF7iW0u9yabqqBXUAEAAAAAQSNFZ4EjSYdhI0EjRWeJASEHQAAgAAAAV2AE0AAAAAq83vqxI0mHYSNBI0VniQEkzZZBBDgeZh+h+gXEmOrSFtVvkUcnHWj/rfPW7iJ0G3UJ8zpuBmUM/VjOMJCY4+eDqdTiPIwX+/vNXegc8FZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsAA==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "__safeContent__": [ + { + "$binary": { + "base64": "ThpoKfQ8AkOzkFfNC1+9PF0pY2nIzfXvRdxQgjkNbBw=", + "subType": "00" + } + } + ] + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json b/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json new file mode 100644 index 000000000..46da99cbf --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json @@ -0,0 +1,232 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + }, + { + "_id": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "Compact works", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "runCommand", + "object": "database", + "command_name": "compactStructuredEncryptionData", + "arguments": { + "command": { + "compactStructuredEncryptionData": "default" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "compactStructuredEncryptionData": "default", + "compactionTokens": { + "encryptedIndexed": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + }, + "encryptedUnindexed": { + "$binary": { + "base64": "SWO8WEoZ2r2Kx/muQKb7+COizy85nIIUFiHh4K9kcvA=", + "subType": "00" + } + } + } + }, + "command_name": "compactStructuredEncryptionData" + } + } + ] + }, + { + "description": "Compact errors on an unencrypted client", + "operations": [ + { + "name": "runCommand", + "object": "database", + "command_name": "compactStructuredEncryptionData", + "arguments": { + "command": { + "compactStructuredEncryptionData": "default" + } + }, + "result": { + "errorContains": "'compactStructuredEncryptionData.compactionTokens' is missing" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json new file mode 100644 index 000000000..6836f40e0 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json @@ -0,0 +1,2239 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "tests": [ + { + "description": "state collections and index are created", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + } + ] + }, + { + "description": "default state collection names are applied", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + }, + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "enxcol_.encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "enxcol_.encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "enxcol_.encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + }, + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + } + ] + }, + { + "description": "drop removes all state collections", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + }, + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + }, + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "enxcol_.encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "enxcol_.encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "enxcol_.encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "enxcol_.encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + }, + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "enxcol_.encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + } + ] + }, + { + "description": "encryptedFieldsMap with cyclic entries does not loop", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + }, + "default.encryptedCollection.esc": { + "escCollection": "encryptedCollection", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + } + ] + }, + { + "description": "CreateCollection without encryptedFields.", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "plaintextCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "plaintextCollection" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "plaintextCollection" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "plaintextCollection" + } + }, + "command_name": "listCollections", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "plaintextCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "plaintextCollection" + }, + "command_name": "create", + "database_name": "default" + } + } + ] + }, + { + "description": "CreateCollection from encryptedFieldsMap.", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + } + ] + }, + { + "description": "CreateCollection from encryptedFields.", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "encryptedCollection" + } + }, + "command_name": "listCollections", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + } + ] + }, + { + "description": "DropCollection from encryptedFieldsMap", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + } + ] + }, + { + "description": "DropCollection from encryptedFields", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": {} + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + }, + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "encryptedCollection" + } + }, + "command_name": "listCollections", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + } + ] + }, + { + "description": "DropCollection from remote encryptedFields", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + }, + "encryptedFieldsMap": {} + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "__safeContent___1" + } + }, + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.esc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection.ecoc" + } + }, + { + "name": "assertCollectionNotExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.esc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection.ecoc", + "clusteredIndex": { + "key": { + "_id": 1 + }, + "unique": true + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "create": "encryptedCollection", + "encryptedFields": { + "escCollection": "encryptedCollection.esc", + "eccCollection": "encryptedCollection.ecc", + "ecocCollection": "encryptedCollection.ecoc", + "fields": [ + { + "path": "firstName", + "bsonType": "string", + "keyId": { + "$binary": { + "subType": "04", + "base64": "AAAAAAAAAAAAAAAAAAAAAA==" + } + } + } + ] + } + }, + "command_name": "create", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "encryptedCollection" + } + }, + "command_name": "listCollections", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "__safeContent___1", + "key": { + "__safeContent__": 1 + } + } + ] + }, + "command_name": "createIndexes", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "encryptedCollection" + } + }, + "command_name": "listCollections", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.esc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection.ecoc" + }, + "command_name": "drop", + "database_name": "default" + } + }, + { + "command_started_event": { + "command": { + "drop": "encryptedCollection" + }, + "command_name": "drop", + "database_name": "default" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json b/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json new file mode 100644 index 000000000..c6d0bca0d --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json @@ -0,0 +1,148 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "_id": 1, + "encryptedUnindexed": { + "$binary": { + "base64": "BqvN76sSNJh2EjQSNFZ4kBICTQaVZPWgXp41I7mPV1rLFTtw1tXzjcdSEyxpKKqujlko5TeizkB9hHQ009dVY1+fgIiDcefh+eQrm3CkhQ==", + "subType": "06" + } + } + } + ], + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "FLE2 decrypt of existing data succeeds", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encryptedUnindexed": "value123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json new file mode 100644 index 000000000..790e81829 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json @@ -0,0 +1,305 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "Delete can query an FLE2 indexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "value123" + } + } + }, + { + "name": "deleteOne", + "arguments": { + "filter": { + "encryptedIndexed": "value123" + } + }, + "result": { + "deletedCount": 1 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "delete": "default", + "deletes": [ + { + "q": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "limit": 1 + } + ], + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + }, + "deleteTokens": { + "default.default": { + "encryptedIndexed": { + "e": { + "$binary": { + "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=", + "subType": "00" + } + }, + "o": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + } + } + } + } + } + }, + "command_name": "delete" + } + } + ], + "outcome": { + "collection": { + "data": [] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json new file mode 100644 index 000000000..ea3eb4850 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json @@ -0,0 +1,217 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "encryptedFieldsMap is preferred over remote encryptedFields", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.default": { + "escCollection": "esc", + "eccCollection": "ecc", + "ecocCollection": "ecoc", + "fields": [] + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedUnindexed": { + "$binary": { + "base64": "BqvN76sSNJh2EjQSNFZ4kBICTQaVZPWgXp41I7mPV1rLFTtw1tXzjcdSEyxpKKqujlko5TeizkB9hHQ009dVY1+fgIiDcefh+eQrm3CkhQ==", + "subType": "06" + } + } + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encryptedUnindexed": "value123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedUnindexed": { + "$binary": { + "base64": "BqvN76sSNJh2EjQSNFZ4kBICTQaVZPWgXp41I7mPV1rLFTtw1tXzjcdSEyxpKKqujlko5TeizkB9hHQ009dVY1+fgIiDcefh+eQrm3CkhQ==", + "subType": "06" + } + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": 1 + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedUnindexed": { + "$binary": { + "base64": "BqvN76sSNJh2EjQSNFZ4kBICTQaVZPWgXp41I7mPV1rLFTtw1tXzjcdSEyxpKKqujlko5TeizkB9hHQ009dVY1+fgIiDcefh+eQrm3CkhQ==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json new file mode 100644 index 000000000..69abfa7cf --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json @@ -0,0 +1,304 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "json_schema": { + "properties": {}, + "bsonType": "object" + }, + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "encryptedFields is preferred over jsonSchema", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "123" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "encryptedIndexed": "123" + } + }, + "result": [ + { + "_id": 1, + "encryptedIndexed": "123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "__safeContent__": [ + { + "$binary": { + "base64": "31eCYlbQoVboc5zwC8IoyJVSkag9PxREka8dkmbXJeY=", + "subType": "00" + } + } + ] + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json new file mode 100644 index 000000000..030952e05 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json @@ -0,0 +1,105 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "key_vault_data": [], + "tests": [ + { + "description": "default state collections are applied to encryptionInformation", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.default": { + "fields": [] + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "foo": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAE8KGPgq7h3n9nH5lfHcia8wtOTLwGkZNLBesb6PULqbBXMAIAAAAACq0558QyD3c3jkR5k0Zc9UpQK8ByhXhtn2d1xVQnuJ3AVjACAAAAAA1003zUWGwD4zVZ0KeihnZOthS3V6CEHUfnJZcIYHefISY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "foo": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAE8KGPgq7h3n9nH5lfHcia8wtOTLwGkZNLBesb6PULqbBXMAIAAAAACq0558QyD3c3jkR5k0Zc9UpQK8ByhXhtn2d1xVQnuJ3AVjACAAAAAA1003zUWGwD4zVZ0KeihnZOthS3V6CEHUfnJZcIYHefISY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + ], + "encryptionInformation": { + "type": { + "$numberInt": "1" + }, + "schema": { + "default.default": { + "fields": [], + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc" + } + } + }, + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "foo": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAE8KGPgq7h3n9nH5lfHcia8wtOTLwGkZNLBesb6PULqbBXMAIAAAAACq0558QyD3c3jkR5k0Zc9UpQK8ByhXhtn2d1xVQnuJ3AVjACAAAAAA1003zUWGwD4zVZ0KeihnZOthS3V6CEHUfnJZcIYHefISY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json new file mode 100644 index 000000000..b8088515c --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json @@ -0,0 +1,602 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "findOneAndUpdate can query an FLE2 indexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "value123" + } + } + }, + { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "encryptedIndexed": "value123" + }, + "update": { + "$set": { + "foo": "bar" + } + }, + "returnDocument": "Before" + }, + "result": { + "_id": 1, + "encryptedIndexed": "value123" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default", + "query": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "update": { + "$set": { + "foo": "bar" + } + }, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + }, + "deleteTokens": { + "default.default": { + "encryptedIndexed": { + "e": { + "$binary": { + "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=", + "subType": "00" + } + }, + "o": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + } + } + } + } + } + }, + "command_name": "findAndModify" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "foo": "bar", + "__safeContent__": [ + { + "$binary": { + "base64": "ThpoKfQ8AkOzkFfNC1+9PF0pY2nIzfXvRdxQgjkNbBw=", + "subType": "00" + } + } + ] + } + ] + } + } + }, + { + "description": "findOneAndUpdate can modify an FLE2 indexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "value123" + } + } + }, + { + "name": "findOneAndUpdate", + "arguments": { + "filter": { + "encryptedIndexed": "value123" + }, + "update": { + "$set": { + "encryptedIndexed": "value456" + } + }, + "returnDocument": "Before" + }, + "result": { + "_id": 1, + "encryptedIndexed": "value123" + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "encryptedIndexed": "value456" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default", + "query": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "update": { + "$set": { + "encryptedIndexed": { + "$$type": "binData" + } + } + }, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + }, + "deleteTokens": { + "default.default": { + "encryptedIndexed": { + "e": { + "$binary": { + "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=", + "subType": "00" + } + }, + "o": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + } + } + } + } + } + }, + "command_name": "findAndModify" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": { + "$eq": 1 + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "__safeContent__": [ + { + "$binary": { + "base64": "rhe7/w8Ob8Unl44rGr/moScx6m5VODQnscDhF4Nkn6g=", + "subType": "00" + } + } + ] + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json new file mode 100644 index 000000000..142cacf2f --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json @@ -0,0 +1,300 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "Insert and find FLE2 indexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "123" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "encryptedIndexed": "123" + } + }, + "result": [ + { + "_id": 1, + "encryptedIndexed": "123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "__safeContent__": [ + { + "$binary": { + "base64": "31eCYlbQoVboc5zwC8IoyJVSkag9PxREka8dkmbXJeY=", + "subType": "00" + } + } + ] + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json new file mode 100644 index 000000000..1a7509590 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json @@ -0,0 +1,250 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "Insert and find FLE2 unindexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedUnindexed": "value123" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "_id": 1, + "encryptedUnindexed": "value123" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedUnindexed": { + "$$type": "binData" + } + } + ], + "ordered": true + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": { + "$eq": 1 + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedUnindexed": { + "$$type": "binData" + } + } + ] + } + } + }, + { + "description": "Query with an unindexed field fails", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedUnindexed": "value123" + } + } + }, + { + "name": "find", + "arguments": { + "filter": { + "encryptedUnindexed": "value123" + } + }, + "result": { + "errorContains": "Cannot query" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json b/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json new file mode 100644 index 000000000..2db1cd770 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json @@ -0,0 +1,118 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [ + { + "encryptedUnindexed": { + "$binary": { + "base64": "BqvN76sSNJh2EjQSNFZ4kBICTQaVZPWgXp41I7mPV1rLFTtw1tXzjcdSEyxpKKqujlko5TeizkB9hHQ009dVY1+fgIiDcefh+eQrm3CkhQ==", + "subType": "06" + } + } + } + ], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [], + "tests": [ + { + "description": "FLE2 encrypt fails with mising key", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "123" + } + }, + "result": { + "errorContains": "not all keys requested were satisfied" + } + } + ] + }, + { + "description": "FLE2 decrypt fails with mising key", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "find", + "arguments": { + "filter": {} + }, + "result": { + "errorContains": "not all keys requested were satisfied" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json b/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json new file mode 100644 index 000000000..e9dd586c2 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json @@ -0,0 +1,86 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "key_vault_data": [], + "encrypted_fields": { + "fields": [] + }, + "tests": [ + { + "description": "insert with no encryption succeeds", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "foo": "bar" + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "foo": "bar" + } + ], + "ordered": true + }, + "command_name": "insert" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "foo": "bar" + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json new file mode 100644 index 000000000..66a291902 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json @@ -0,0 +1,610 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "encrypted_fields": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + }, + "key_vault_data": [ + { + "_id": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1648914851981" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ], + "tests": [ + { + "description": "Update can query an FLE2 indexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "value123" + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "encryptedIndexed": "value123" + }, + "update": { + "$set": { + "foo": "bar" + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "u": { + "$set": { + "foo": "bar" + } + } + } + ], + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + }, + "deleteTokens": { + "default.default": { + "encryptedIndexed": { + "e": { + "$binary": { + "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=", + "subType": "00" + } + }, + "o": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + } + } + } + } + } + }, + "command_name": "update" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "foo": "bar", + "__safeContent__": [ + { + "$binary": { + "base64": "ThpoKfQ8AkOzkFfNC1+9PF0pY2nIzfXvRdxQgjkNbBw=", + "subType": "00" + } + } + ] + } + ] + } + } + }, + { + "description": "Update can modify an FLE2 indexed field", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + } + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encryptedIndexed": "value123" + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "encryptedIndexed": "value123" + }, + "update": { + "$set": { + "encryptedIndexed": "value456" + } + } + }, + "result": { + "matchedCount": 1, + "modifiedCount": 1, + "upsertedCount": 0 + } + }, + { + "name": "find", + "arguments": { + "filter": { + "_id": 1 + } + }, + "result": [ + { + "encryptedIndexed": "value456" + } + ] + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "default" + } + }, + "command_name": "listCollections" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + }, + { + "command_started_event": { + "command": { + "insert": "default", + "documents": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + } + } + ], + "ordered": true, + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "command_name": "insert" + } + }, + { + "command_started_event": { + "command": { + "update": "default", + "updates": [ + { + "q": { + "encryptedIndexed": { + "$eq": { + "$binary": { + "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "subType": "06" + } + } + } + }, + "u": { + "$set": { + "encryptedIndexed": { + "$$type": "binData" + } + } + } + } + ], + "encryptionInformation": { + "type": 1, + "schema": { + "default.default": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + }, + "deleteTokens": { + "default.default": { + "encryptedIndexed": { + "e": { + "$binary": { + "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=", + "subType": "00" + } + }, + "o": { + "$binary": { + "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=", + "subType": "00" + } + } + } + } + } + } + }, + "command_name": "update" + } + }, + { + "command_started_event": { + "command": { + "find": "default", + "filter": { + "_id": { + "$eq": 1 + } + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encryptedIndexed": { + "$$type": "binData" + }, + "__safeContent__": [ + { + "$binary": { + "base64": "rhe7/w8Ob8Unl44rGr/moScx6m5VODQnscDhF4Nkn6g=", + "subType": "00" + } + } + ] + } + ] + } + } + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json new file mode 100644 index 000000000..fab36f75a --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json @@ -0,0 +1,520 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0", + "topology": [ + "replicaset", + "sharded" + ] + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "tests": [ + { + "description": "create with a validator on an unencrypted field is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "validator": { + "unencrypted_string": "foo" + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + } + ] + }, + { + "description": "create with a validator on an encrypted field is an error", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "validator": { + "encryptedIndexed": "foo" + } + }, + "result": { + "errorContains": "Comparison to encrypted fields not supported" + } + } + ] + }, + { + "description": "collMod with a validator on an unencrypted field is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "collMod": "encryptedCollection", + "validator": { + "unencrypted_string": "foo" + } + } + } + } + ] + }, + { + "description": "collMod with a validator on an encrypted field is an error", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "collMod": "encryptedCollection", + "validator": { + "encryptedIndexed": "foo" + } + } + }, + "result": { + "errorContains": "Comparison to encrypted fields not supported" + } + } + ] + }, + { + "description": "createIndexes with a partialFilterExpression on an unencrypted field is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "name", + "key": { + "name": 1 + }, + "partialFilterExpression": { + "unencrypted_string": "foo" + } + } + ] + } + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "name" + } + } + ] + }, + { + "description": "createIndexes with a partialFilterExpression on an encrypted field is an error", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "encryptedFieldsMap": { + "default.encryptedCollection": { + "escCollection": "enxcol_.default.esc", + "eccCollection": "enxcol_.default.ecc", + "ecocCollection": "enxcol_.default.ecoc", + "fields": [ + { + "keyId": { + "$binary": { + "base64": "EjRWeBI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedIndexed", + "bsonType": "string", + "queries": { + "queryType": "equality", + "contention": { + "$numberLong": "0" + } + } + }, + { + "keyId": { + "$binary": { + "base64": "q83vqxI0mHYSNBI0VniQEg==", + "subType": "04" + } + }, + "path": "encryptedUnindexed", + "bsonType": "string" + } + ] + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "name", + "key": { + "name": 1 + }, + "partialFilterExpression": { + "encryptedIndexed": "foo" + } + } + ] + } + }, + "result": { + "errorContains": "Comparison to encrypted fields not supported" + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/timeoutMS.json b/tests/SpecTests/client-side-encryption/tests/timeoutMS.json new file mode 100644 index 000000000..443aa0aa2 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/timeoutMS.json @@ -0,0 +1,200 @@ +{ + "runOn": [ + { + "minServerVersion": "4.4" + } + ], + "database_name": "cse-timeouts-db", + "collection_name": "cse-timeouts-coll", + "data": [], + "json_schema": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + }, + "key_vault_data": [ + { + "status": 1, + "_id": { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "keyAltNames": [ + "altname", + "another_altname" + ] + } + ], + "tests": [ + { + "description": "timeoutMS applied to listCollections to get collection schema", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "listCollections" + ], + "blockConnection": true, + "blockTimeMS": 60 + } + }, + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + }, + "timeoutMS": 50 + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + } + }, + "result": { + "isTimeoutError": true + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "listCollections": 1, + "filter": { + "name": "cse-timeouts-coll" + }, + "maxTimeMS": { + "$$type": [ + "int", + "long" + ] + } + }, + "command_name": "listCollections" + } + } + ] + }, + { + "description": "remaining timeoutMS applied to find to get keyvault data", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 3 + }, + "data": { + "failCommands": [ + "listCollections", + "find" + ], + "blockConnection": true, + "blockTimeMS": 20 + } + }, + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "aws": {} + } + }, + "timeoutMS": 50 + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0", + "random": "abc" + } + }, + "result": { + "isTimeoutError": true + } + } + ] + } + ] +} diff --git a/tests/SpecTests/client-side-encryption/tests/validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/validatorAndPartialFieldExpression.json new file mode 100644 index 000000000..e07137ce1 --- /dev/null +++ b/tests/SpecTests/client-side-encryption/tests/validatorAndPartialFieldExpression.json @@ -0,0 +1,642 @@ +{ + "runOn": [ + { + "minServerVersion": "6.0.0" + } + ], + "database_name": "default", + "collection_name": "default", + "data": [], + "tests": [ + { + "description": "create with a validator on an unencrypted field is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "schemaMap": { + "default.encryptedCollection": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "validator": { + "unencrypted_string": "foo" + } + } + }, + { + "name": "assertCollectionExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection" + } + } + ] + }, + { + "description": "create with a validator on an encrypted field is an error", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "schemaMap": { + "default.encryptedCollection": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection", + "validator": { + "encrypted_string": "foo" + } + }, + "result": { + "errorContains": "Comparison to encrypted fields not supported" + } + } + ] + }, + { + "description": "collMod with a validator on an unencrypted field is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "schemaMap": { + "default.encryptedCollection": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "collMod": "encryptedCollection", + "validator": { + "unencrypted_string": "foo" + } + } + } + } + ] + }, + { + "description": "collMod with a validator on an encrypted field is an error", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "schemaMap": { + "default.encryptedCollection": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "collMod": "encryptedCollection", + "validator": { + "encrypted_string": "foo" + } + } + }, + "result": { + "errorContains": "Comparison to encrypted fields not supported" + } + } + ] + }, + { + "description": "createIndexes with a partialFilterExpression on an unencrypted field is OK", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "schemaMap": { + "default.encryptedCollection": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "name", + "key": { + "name": 1 + }, + "partialFilterExpression": { + "unencrypted_string": "foo" + } + } + ] + } + } + }, + { + "name": "assertIndexExists", + "object": "testRunner", + "arguments": { + "database": "default", + "collection": "encryptedCollection", + "index": "name" + } + } + ] + }, + { + "description": "createIndexes with a partialFilterExpression on an encrypted field is an error", + "clientOptions": { + "autoEncryptOpts": { + "kmsProviders": { + "local": { + "key": { + "$binary": { + "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk", + "subType": "00" + } + } + } + }, + "schemaMap": { + "default.encryptedCollection": { + "properties": { + "encrypted_w_altname": { + "encrypt": { + "keyId": "/altname", + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + }, + "random": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random" + } + }, + "encrypted_string_equivalent": { + "encrypt": { + "keyId": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ], + "bsonType": "string", + "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic" + } + } + }, + "bsonType": "object" + } + } + } + }, + "operations": [ + { + "name": "dropCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "createCollection", + "object": "database", + "arguments": { + "collection": "encryptedCollection" + } + }, + { + "name": "runCommand", + "object": "database", + "arguments": { + "command": { + "createIndexes": "encryptedCollection", + "indexes": [ + { + "name": "name", + "key": { + "name": 1 + }, + "partialFilterExpression": { + "encrypted_string": "foo" + } + } + ] + } + }, + "result": { + "errorContains": "Comparison to encrypted fields not supported" + } + } + ] + } + ] +} From dc1bb17f04d0bda1b62e786e034a437f642a47f6 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 3 Jun 2022 09:44:06 -0400 Subject: [PATCH 162/321] PHPLIB-887: Allow extra fields in find results Most operations that use ASSERT_SAME_DOCUMENT and ASSERT_SAME_DOCUMENTS should technically use ASSERT_MATCHES_DOCUMENT and ASSERT_DOCUMENTS_MATCH, respectively; however, this is the minimum change needed to satisfy new CSFLE spec tests. --- tests/SpecTests/FunctionalTestCase.php | 2 +- tests/SpecTests/Operation.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index ff2318f2c..0606e0356 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -89,7 +89,7 @@ public static function assertCommandReplyMatches(stdClass $expected, stdClass $a * @param array|object $actualDocument * @param string $message */ - protected static function assertDocumentsMatch($expectedDocument, $actualDocument, string $message = ''): void + public static function assertDocumentsMatch($expectedDocument, $actualDocument, string $message = ''): void { $constraint = new DocumentsMatchConstraint($expectedDocument, true, true); diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index 8ff103916..dc5cd2b37 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -774,10 +774,10 @@ private function getResultAssertionTypeForCollection() case 'findOneAndDelete': case 'findOneAndReplace': case 'findOneAndUpdate': - return ResultExpectation::ASSERT_SAME_DOCUMENT; + return ResultExpectation::ASSERT_MATCHES_DOCUMENT; case 'find': - return ResultExpectation::ASSERT_SAME_DOCUMENTS; + return ResultExpectation::ASSERT_DOCUMENTS_MATCH; case 'insertMany': return ResultExpectation::ASSERT_INSERTMANY; From 1ee12434e13f17b57ccbe39af7279a84ab9dfe8e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 6 Jun 2022 15:20:24 -0400 Subject: [PATCH 163/321] Use more flexible command assertion in testDataKeyAndDoubleEncryption --- .../SpecTests/ClientSideEncryptionSpecTest.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index ce5a607e8..ee0860a89 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -240,9 +240,9 @@ public function testDataKeyAndDoubleEncryption(string $providerName, $masterKey) $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncryption = $clientEncrypted->createClientEncryption($encryptionOpts); - $commands = []; - $dataKeyId = null; + $insertCommand = null; + $keyAltName = $providerName . '_altname'; (new CommandObserver())->observe( @@ -254,18 +254,20 @@ function () use ($clientEncryption, &$dataKeyId, $keyAltName, $providerName, $ma $dataKeyId = $clientEncryption->createDataKey($providerName, $keyData); }, - function ($command) use (&$commands): void { - $commands[] = $command; + function ($command) use (&$insertCommand): void { + if ($command['started']->getCommandName() === 'insert') { + $insertCommand = $command['started']->getCommand(); + } } ); $this->assertInstanceOf(Binary::class, $dataKeyId); $this->assertSame(Binary::TYPE_UUID, $dataKeyId->getType()); - $this->assertCount(2, $commands); - $insert = $commands[1]['started']; - $this->assertSame('insert', $insert->getCommandName()); - $this->assertSame(WriteConcern::MAJORITY, $insert->getCommand()->writeConcern->w); + $this->assertNotNull($insertCommand); + $this->assertObjectHasAttribute('writeConcern', $insertCommand); + $this->assertObjectHasAttribute('w', $insertCommand->writeConcern); + $this->assertSame(WriteConcern::MAJORITY, $insertCommand->writeConcern->w); $keys = $client->selectCollection('keyvault', 'datakeys')->find(['_id' => $dataKeyId]); $keys = iterator_to_array($keys); From 32a1cf892909d631e4b82df9ddb22f10fc2781e1 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Tue, 7 Jun 2022 18:27:34 +0300 Subject: [PATCH 164/321] PHPLIB-749: Support comment option on command helpers (#925) Co-authored-by: Jeremy Mikola --- ...goDBClient-method-dropDatabase-option.yaml | 9 ++++ ...oDBClient-method-listDatabases-option.yaml | 9 ++++ ...rgs-MongoDBClient-method-watch-option.yaml | 9 ++++ ...oDBCollection-method-aggregate-option.yaml | 5 +- ...oDBCollection-method-bulkWrite-option.yaml | 9 ++++ ...MongoDBCollection-method-count-option.yaml | 9 ++++ ...llection-method-countDocuments-option.yaml | 7 +++ ...BCollection-method-createIndex-option.yaml | 9 ++++ ...ollection-method-createIndexes-option.yaml | 9 ++++ ...DBCollection-method-deleteMany-option.yaml | 9 ++++ ...oDBCollection-method-deleteOne-option.yaml | 9 ++++ ...goDBCollection-method-distinct-option.yaml | 9 ++++ ...-MongoDBCollection-method-drop-option.yaml | 9 ++++ ...oDBCollection-method-dropIndex-option.yaml | 9 ++++ ...BCollection-method-dropIndexes-option.yaml | 9 ++++ ...n-method-estimateDocumentCount-option.yaml | 9 ++++ ...ngoDBCollection-method-explain-option.yaml | 11 ++++ ...-MongoDBCollection-method-find-option.yaml | 15 +++--- ...ection-method-findOneAndDelete-option.yaml | 9 ++++ ...ction-method-findOneAndReplace-option.yaml | 9 ++++ ...ection-method-findOneAndUpdate-option.yaml | 9 ++++ ...DBCollection-method-insertMany-option.yaml | 9 ++++ ...oDBCollection-method-insertOne-option.yaml | 9 ++++ ...BCollection-method-listIndexes-option.yaml | 9 ++++ ...oDBCollection-method-mapReduce-option.yaml | 9 ++++ ...ongoDBCollection-method-rename-option.yaml | 9 ++++ ...DBCollection-method-replaceOne-option.yaml | 9 ++++ ...DBCollection-method-updateMany-option.yaml | 9 ++++ ...oDBCollection-method-updateOne-option.yaml | 9 ++++ ...MongoDBCollection-method-watch-option.yaml | 9 ++++ ...ngoDBDatabase-method-aggregate-option.yaml | 5 +- ...tabase-method-createCollection-option.yaml | 9 ++++ ...gs-MongoDBDatabase-method-drop-option.yaml | 9 ++++ ...Database-method-dropCollection-option.yaml | 9 ++++ ...atabase-method-listCollections-option.yaml | 9 ++++ ...tabase-method-modifyCollection-option.yaml | 9 ++++ ...tabase-method-renameCollection-option.yaml | 9 ++++ ...s-MongoDBDatabase-method-watch-option.yaml | 9 ++++ docs/includes/apiargs-aggregate-option.yaml | 10 ---- docs/includes/apiargs-common-option.yaml | 12 +++++ src/Command/ListCollections.php | 24 +++++++-- src/Command/ListDatabases.php | 34 ++++++++---- src/Operation/Aggregate.php | 9 ++-- src/Operation/BulkWrite.php | 11 +++- src/Operation/Count.php | 6 ++- src/Operation/CountDocuments.php | 6 ++- src/Operation/CreateCollection.php | 6 ++- src/Operation/CreateIndexes.php | 10 +++- src/Operation/Delete.php | 8 +++ src/Operation/DeleteMany.php | 4 ++ src/Operation/DeleteOne.php | 4 ++ src/Operation/Distinct.php | 10 +++- src/Operation/DropCollection.php | 24 +++++++-- src/Operation/DropDatabase.php | 23 +++++++- src/Operation/DropIndexes.php | 10 +++- src/Operation/EstimatedDocumentCount.php | 6 ++- src/Operation/Explain.php | 31 ++++++++--- src/Operation/Find.php | 9 ++-- src/Operation/FindAndModify.php | 6 ++- src/Operation/FindOne.php | 5 +- src/Operation/FindOneAndDelete.php | 4 ++ src/Operation/FindOneAndReplace.php | 4 ++ src/Operation/FindOneAndUpdate.php | 4 ++ src/Operation/InsertMany.php | 11 +++- src/Operation/InsertOne.php | 10 +++- src/Operation/ListCollectionNames.php | 4 ++ src/Operation/ListCollections.php | 4 ++ src/Operation/ListDatabaseNames.php | 4 ++ src/Operation/ListDatabases.php | 4 ++ src/Operation/ListIndexes.php | 10 +++- src/Operation/MapReduce.php | 6 ++- src/Operation/ModifyCollection.php | 17 +++++- src/Operation/RenameCollection.php | 34 ++++++++---- src/Operation/ReplaceOne.php | 4 ++ src/Operation/Update.php | 10 +++- src/Operation/UpdateMany.php | 4 ++ src/Operation/UpdateOne.php | 4 ++ src/Operation/Watch.php | 6 ++- tests/Operation/AggregateTest.php | 4 -- tests/Operation/FindTest.php | 4 -- tests/UnifiedSpecTests/UnifiedSpecTest.php | 52 ------------------- tests/UnifiedSpecTests/Util.php | 44 ++++++++-------- 82 files changed, 679 insertions(+), 177 deletions(-) diff --git a/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml b/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml index 07e75df74..be0a19aa9 100644 --- a/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-dropDatabase-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml b/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml index fa544cce0..38baf93ad 100644 --- a/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-listDatabases-option.yaml @@ -13,6 +13,15 @@ interface: phpmethod operation: ~ optional: true --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- arg_name: option name: filter type: array|object diff --git a/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml b/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml index 7fa5400a8..96d11eacb 100644 --- a/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml @@ -7,6 +7,15 @@ source: file: apiargs-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. + + .. versionadded:: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: fullDocument diff --git a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml index a2fc460d9..b3d19c3e5 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-aggregate-option.yaml @@ -11,9 +11,12 @@ source: ref: bypassDocumentValidation --- source: - file: apiargs-aggregate-option.yaml + file: apiargs-common-option.yaml ref: comment post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. + .. versionadded:: 1.3 --- source: diff --git a/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml index 7949954d6..25d8e24d3 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-bulkWrite-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: bypassDocumentValidation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: let diff --git a/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml index 62227f1cc..3d839e04a 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-count-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- arg_name: option name: hint type: string|array|object diff --git a/docs/includes/apiargs-MongoDBCollection-method-countDocuments-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-countDocuments-option.yaml index 2571b0716..da1f01138 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-countDocuments-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-countDocuments-option.yaml @@ -2,6 +2,13 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. +--- arg_name: option name: hint type: string|array|object diff --git a/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml index 18d1ce07e..182837674 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-createIndex-option.yaml @@ -17,6 +17,15 @@ interface: phpmethod operation: ~ optional: true --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- arg_name: option name: unique type: boolean diff --git a/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml index 5728ab31b..54c33bfa0 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-createIndexes-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-MongoDBCollection-method-createIndex-option.yaml ref: commitQuorum diff --git a/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml index b11e4f5f1..110911f51 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-deleteMany-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml index b11e4f5f1..110911f51 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-deleteOne-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml index 3c2ae6ed2..05a1b2853 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-distinct-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml index 7e08cf431..5eb5efaba 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-drop-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-dropCollection-option.yaml ref: encryptedFields diff --git a/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml index 9bc36f4bf..b87e09b74 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-dropIndex-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml index 0aa5048f2..aff9f4d75 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-dropIndexes-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-estimateDocumentCount-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-estimateDocumentCount-option.yaml index f70487a16..7289296e9 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-estimateDocumentCount-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-estimateDocumentCount-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-explain-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-explain-option.yaml index 7c6a4dcd0..650633bce 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-explain-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-explain-option.yaml @@ -1,3 +1,14 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + Defaults to the ``comment`` of the explained operation (if any). + + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-MongoDBCollection-common-option.yaml ref: readPreference diff --git a/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml index e80f2365f..1b01599ec 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-find-option.yaml @@ -74,15 +74,12 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- -arg_name: option -name: comment -type: string -description: | - A comment to attach to the query to help interpret and trace query - :dbcommand:`profile` data. -interface: phpmethod -operation: ~ -optional: true +source: + file: apiargs-common-option.yaml + ref: comment +post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. --- arg_name: option name: cursorType diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml index 062700579..d8f2b3a4a 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndDelete-option.yaml @@ -10,6 +10,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml index 37f326cf0..b509ac947 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndReplace-option.yaml @@ -10,6 +10,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml index 412125239..a8f895f1b 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-findOneAndUpdate-option.yaml @@ -16,6 +16,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml index 391935780..60f197d2b 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-insertMany-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: bypassDocumentValidation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-MongoDBCollection-method-bulkWrite-option.yaml ref: ordered diff --git a/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml index 61d795c76..adf17cb61 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-insertOne-option.yaml @@ -2,6 +2,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: bypassDocumentValidation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml index cbfb65016..aa939b950 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-listIndexes-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: maxTimeMS diff --git a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml index 97f320ee1..478d12dda 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-mapReduce-option.yaml @@ -8,6 +8,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- arg_name: option name: finalize type: :php:`MongoDB\\BSON\\Javascript ` diff --git a/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml index 3aed74eb2..0b0b0809c 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-rename-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-MongoDBCollection-common-option.yaml ref: typeMap diff --git a/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml index dcd0847b8..676296d26 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-replaceOne-option.yaml @@ -10,6 +10,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml index e102f5613..64eec34e0 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-updateMany-option.yaml @@ -16,6 +16,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml index e102f5613..64eec34e0 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-updateOne-option.yaml @@ -16,6 +16,15 @@ source: file: apiargs-MongoDBCollection-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: hint diff --git a/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml index d785b471e..d1c426229 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml @@ -7,6 +7,15 @@ source: file: apiargs-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. + + .. versionadded:: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: fullDocument diff --git a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml index f24d99d2c..f59192a0f 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-aggregate-option.yaml @@ -11,8 +11,11 @@ source: ref: bypassDocumentValidation --- source: - file: apiargs-aggregate-option.yaml + file: apiargs-common-option.yaml ref: comment +post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. --- source: file: apiargs-aggregate-option.yaml diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index 82865dc16..f95b406c2 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -67,6 +67,15 @@ pre: | Specifies the :manual:`collation ` for the collection. --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- arg_name: option name: encryptedFields type: document diff --git a/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml index 5b3c18c33..e725fc1be 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-drop-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml index f08f9e060..0034b5e88 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-dropCollection-option.yaml @@ -4,6 +4,15 @@ source: post: | .. versionadded:: 1.13 --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml index 49f41dacb..bacf7280a 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-listCollections-option.yaml @@ -13,6 +13,15 @@ interface: phpmethod operation: ~ optional: true --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- arg_name: option name: filter type: array|object diff --git a/docs/includes/apiargs-MongoDBDatabase-method-modifyCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-modifyCollection-option.yaml index ca8d6fef1..b27c16cfb 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-modifyCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-modifyCollection-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml index bf7d96638..bb026bd9c 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-renameCollection-option.yaml @@ -1,3 +1,12 @@ +source: + file: apiargs-common-option.yaml + ref: comment +post: | + This is not supported for server versions prior to 4.4 and will result in an + exception at execution time if used. + + .. versionadded:: 1.13 +--- source: file: apiargs-common-option.yaml ref: session diff --git a/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml index 7de7df6d2..3ee3c1446 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml @@ -7,6 +7,15 @@ source: file: apiargs-common-option.yaml ref: collation --- +source: + file: apiargs-common-option.yaml + ref: comment +post: | + The comment can be any valid BSON type for server versions 4.4 and above. + Earlier server versions only support string values. + + .. versionadded:: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: fullDocument diff --git a/docs/includes/apiargs-aggregate-option.yaml b/docs/includes/apiargs-aggregate-option.yaml index 77d6d535e..c75880df2 100644 --- a/docs/includes/apiargs-aggregate-option.yaml +++ b/docs/includes/apiargs-aggregate-option.yaml @@ -27,16 +27,6 @@ post: | :ref:`$out ` stages. --- arg_name: option -name: comment -type: string -description: | - Users can specify an arbitrary string to help trace the operation through the - database profiler, currentOp, and logs. -interface: phpmethod -operation: ~ -optional: true ---- -arg_name: option name: explain type: boolean description: | diff --git a/docs/includes/apiargs-common-option.yaml b/docs/includes/apiargs-common-option.yaml index 667b35bdb..cae141871 100644 --- a/docs/includes/apiargs-common-option.yaml +++ b/docs/includes/apiargs-common-option.yaml @@ -13,6 +13,18 @@ operation: ~ optional: true --- arg_name: option +name: comment +type: mixed +description: | + Enables users to specify an arbitrary comment to help trace the operation + through the :manual:`database profiler `, + :manual:`currentOp ` output, and + :manual:`logs `. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: hint type: string|array|object description: | diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index 100604170..8a017558f 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -54,6 +54,10 @@ class ListCollections implements Executable * * For servers < 4.0, this option is ignored. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * filter (document): Query by which to filter collections. * * * maxTimeMS (integer): The maximum amount of time to allow the query to @@ -104,6 +108,19 @@ public function __construct($databaseName, array $options = []) * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) + { + $cursor = $server->executeReadCommand($this->databaseName, $this->createCommand(), $this->createOptions()); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + + return new CachingIterator($cursor); + } + + /** + * Create the listCollections command. + * + * @return Command + */ + private function createCommand() { $cmd = ['listCollections' => 1]; @@ -111,16 +128,13 @@ public function execute(Server $server) $cmd['filter'] = (object) $this->options['filter']; } - foreach (['authorizedCollections', 'maxTimeMS', 'nameOnly'] as $option) { + foreach (['authorizedCollections', 'comment', 'maxTimeMS', 'nameOnly'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } } - $cursor = $server->executeReadCommand($this->databaseName, new Command($cmd), $this->createOptions()); - $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); - - return new CachingIterator($cursor); + return new Command($cmd); } /** diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index 20c03157f..3d75fa96c 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -52,6 +52,10 @@ class ListDatabases implements Executable * * For servers < 4.0.5, this option is ignored. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * filter (document): Query by which to filter databases. * * * maxTimeMS (integer): The maximum amount of time to allow the query to @@ -101,6 +105,24 @@ public function __construct(array $options = []) * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ public function execute(Server $server) + { + $cursor = $server->executeReadCommand('admin', $this->createCommand(), $this->createOptions()); + $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); + $result = current($cursor->toArray()); + + if (! isset($result['databases']) || ! is_array($result['databases'])) { + throw new UnexpectedValueException('listDatabases command did not return a "databases" array'); + } + + return $result['databases']; + } + + /** + * Create the listDatabases command. + * + * @return Command + */ + private function createCommand() { $cmd = ['listDatabases' => 1]; @@ -108,21 +130,13 @@ public function execute(Server $server) $cmd['filter'] = (object) $this->options['filter']; } - foreach (['authorizedDatabases', 'maxTimeMS', 'nameOnly'] as $option) { + foreach (['authorizedDatabases', 'comment', 'maxTimeMS', 'nameOnly'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } } - $cursor = $server->executeReadCommand('admin', new Command($cmd), $this->createOptions()); - $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); - $result = current($cursor->toArray()); - - if (! isset($result['databases']) || ! is_array($result['databases'])) { - throw new UnexpectedValueException('listDatabases command did not return a "databases" array'); - } - - return $result['databases']; + return new Command($cmd); } /** diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index 1573c5d94..de3c1e4f0 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -86,8 +86,9 @@ class Aggregate implements Executable, Explainable * * * collation (document): Collation specification. * - * * comment (string): An arbitrary string to help trace the operation - * through the database profiler, currentOp, and logs. + * * comment (mixed): BSON value to attach as a comment to this command. + * + * Only string values are supported for server versions < 4.4. * * * explain (boolean): Specifies whether or not to return the information * on the processing of the pipeline. @@ -170,10 +171,6 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); } - if (isset($options['comment']) && ! is_string($options['comment'])) { - throw InvalidArgumentException::invalidType('"comment" option', $options['comment'], 'string'); - } - if (isset($options['explain']) && ! is_bool($options['explain'])) { throw InvalidArgumentException::invalidType('"explain" option', $options['explain'], 'boolean'); } diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index e80c562b5..f9096c2c5 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -103,6 +103,11 @@ class BulkWrite implements Executable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. The default is false. * + * * comment (mixed): BSON value to attach as a comment to this command(s) + * associated with this bulk write. + * + * This is not supported for servers versions < 4.4. + * * * ordered (boolean): If true, when an insert fails, return without * performing the remaining writes. If false, when a write fails, * continue with the remaining writes, if any. The default is true. @@ -353,8 +358,10 @@ private function createBulkWriteOptions() { $options = ['ordered' => $this->options['ordered']]; - if (isset($this->options['bypassDocumentValidation'])) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + foreach (['bypassDocumentValidation', 'comment'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = $this->options[$option]; + } } if (isset($this->options['let'])) { diff --git a/src/Operation/Count.php b/src/Operation/Count.php index 4d76f0a78..aff947b72 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -62,6 +62,10 @@ class Count implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -195,7 +199,7 @@ private function createCommandDocument() $cmd['hint'] = is_array($this->options['hint']) ? (object) $this->options['hint'] : $this->options['hint']; } - foreach (['limit', 'maxTimeMS', 'skip'] as $option) { + foreach (['comment', 'limit', 'maxTimeMS', 'skip'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index 6771d8d95..6e0e561f9 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -65,6 +65,10 @@ class CountDocuments implements Executable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * Only string values are supported for server versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -107,7 +111,7 @@ public function __construct($databaseName, $collectionName, $filter, array $opti $this->collectionName = (string) $collectionName; $this->filter = $filter; - $this->aggregateOptions = array_intersect_key($options, ['collation' => 1, 'hint' => 1, 'maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); + $this->aggregateOptions = array_intersect_key($options, ['collation' => 1, 'comment' => 1, 'hint' => 1, 'maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); $this->countOptions = array_intersect_key($options, ['limit' => 1, 'skip' => 1]); $this->aggregate = $this->createAggregate(); diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index 5e0d54d22..61c687730 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -72,6 +72,10 @@ class CreateCollection implements Executable * * capped (boolean): Specify true to create a capped collection. If set, * the size option must also be specified. The default is false. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * changeStreamPreAndPostImages (document): Used to configure support for * pre- and post-images in change streams. * @@ -285,7 +289,7 @@ private function createCommand() { $cmd = ['create' => $this->collectionName]; - foreach (['autoIndexId', 'capped', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'pipeline', 'size', 'validationAction', 'validationLevel', 'viewOn'] as $option) { + foreach (['autoIndexId', 'capped', 'comment', 'expireAfterSeconds', 'flags', 'max', 'maxTimeMS', 'pipeline', 'size', 'validationAction', 'validationLevel', 'viewOn'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php index 5778960c9..498b8c1ef 100644 --- a/src/Operation/CreateIndexes.php +++ b/src/Operation/CreateIndexes.php @@ -63,6 +63,10 @@ class CreateIndexes implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * commitQuorum (integer|string): Specifies how many data-bearing members * of a replica set, including the primary, must complete the index * builds successfully before the primary marks the indexes as ready. @@ -195,8 +199,10 @@ private function executeCommand(Server $server) $cmd['commitQuorum'] = $this->options['commitQuorum']; } - if (isset($this->options['maxTimeMS'])) { - $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + foreach (['comment', 'maxTimeMS'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } $server->executeWriteCommand($this->databaseName, new Command($cmd), $this->createOptions()); diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index a52d45bdf..95df96624 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -68,6 +68,10 @@ class Delete implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -194,6 +198,10 @@ private function createBulkWriteOptions(): array { $options = []; + if (isset($this->options['comment'])) { + $options['comment'] = $this->options['comment']; + } + if (isset($this->options['let'])) { $options['let'] = (object) $this->options['let']; } diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index d72c22ab7..3e3a73d0f 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -42,6 +42,10 @@ class DeleteMany implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index 91b47954e..dda930208 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -42,6 +42,10 @@ class DeleteOne implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index aefee694c..3298cda89 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -64,6 +64,10 @@ class Distinct implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * @@ -187,8 +191,10 @@ private function createCommandDocument() $cmd['collation'] = (object) $this->options['collation']; } - if (isset($this->options['maxTimeMS'])) { - $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + foreach (['comment', 'maxTimeMS'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } return $cmd; diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 2eb77890c..2ab9b8716 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -55,6 +55,10 @@ class DropCollection implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * session (MongoDB\Driver\Session): Client session. * * * typeMap (array): Type map for BSON deserialization. This will be used @@ -106,10 +110,8 @@ public function execute(Server $server) throw UnsupportedException::writeConcernNotSupportedInTransaction(); } - $command = new Command(['drop' => $this->collectionName]); - try { - $cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions()); + $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions()); } catch (CommandException $e) { /* The server may return an error if the collection does not exist. * Check for an error code and return the command reply instead of @@ -128,6 +130,22 @@ public function execute(Server $server) return current($cursor->toArray()); } + /** + * Create the drop command. + * + * @return Command + */ + private function createCommand() + { + $cmd = ['drop' => $this->collectionName]; + + if (isset($this->options['comment'])) { + $cmd['comment'] = $this->options['comment']; + } + + return new Command($cmd); + } + /** * Create options for executing the command. * diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php index 6d7e61713..0e569f068 100644 --- a/src/Operation/DropDatabase.php +++ b/src/Operation/DropDatabase.php @@ -48,6 +48,10 @@ class DropDatabase implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * session (MongoDB\Driver\Session): Client session. * * * typeMap (array): Type map for BSON deserialization. This will be used @@ -91,8 +95,7 @@ public function __construct($databaseName, array $options = []) */ public function execute(Server $server) { - $command = new Command(['dropDatabase' => 1]); - $cursor = $server->executeWriteCommand($this->databaseName, $command, $this->createOptions()); + $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions()); if (isset($this->options['typeMap'])) { $cursor->setTypeMap($this->options['typeMap']); @@ -101,6 +104,22 @@ public function execute(Server $server) return current($cursor->toArray()); } + /** + * Create the dropDatabase command. + * + * @return Command + */ + private function createCommand() + { + $cmd = ['dropDatabase' => 1]; + + if (isset($this->options['comment'])) { + $cmd['comment'] = $this->options['comment']; + } + + return new Command($cmd); + } + /** * Create options for executing the command. * diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php index 170cf9875..e63be7fd1 100644 --- a/src/Operation/DropIndexes.php +++ b/src/Operation/DropIndexes.php @@ -55,6 +55,10 @@ class DropIndexes implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * @@ -142,8 +146,10 @@ private function createCommand() 'index' => $this->indexName, ]; - if (isset($this->options['maxTimeMS'])) { - $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + foreach (['comment', 'maxTimeMS'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } return new Command($cmd); diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index e4e731eec..5ed9c73b9 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -59,6 +59,10 @@ class EstimatedDocumentCount implements Executable, Explainable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * @@ -94,7 +98,7 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); } - $this->options = array_intersect_key($options, ['maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); + $this->options = array_intersect_key($options, ['comment' => 1, 'maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); } /** diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php index 862e9a152..b6cec43e3 100644 --- a/src/Operation/Explain.php +++ b/src/Operation/Explain.php @@ -60,6 +60,10 @@ class Explain implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * readPreference (MongoDB\Driver\ReadPreference): Read preference. * * * session (MongoDB\Driver\Session): Client session. @@ -112,13 +116,7 @@ public function execute(Server $server) throw UnsupportedException::explainNotSupported(); } - $cmd = ['explain' => $this->explainable->getCommandDocument($server)]; - - if (isset($this->options['verbosity'])) { - $cmd['verbosity'] = $this->options['verbosity']; - } - - $cursor = $server->executeCommand($this->databaseName, new Command($cmd), $this->createOptions()); + $cursor = $server->executeCommand($this->databaseName, $this->createCommand($server), $this->createOptions()); if (isset($this->options['typeMap'])) { $cursor->setTypeMap($this->options['typeMap']); @@ -127,6 +125,25 @@ public function execute(Server $server) return current($cursor->toArray()); } + /** + * Create the explain command. + * + * @param Server $server + * @return Command + */ + private function createCommand(Server $server) + { + $cmd = ['explain' => $this->explainable->getCommandDocument($server)]; + + foreach (['comment', 'verbosity'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } + } + + return new Command($cmd); + } + /** * Create options for executing the command. * diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 5371243dd..77e20ba12 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -78,8 +78,9 @@ class Find implements Executable, Explainable * * * collation (document): Collation specification. * - * * comment (string): Attaches a comment to the query. If "$comment" also - * exists in the modifiers document, this option will take precedence. + * * comment (mixed): BSON value to attach as a comment to this command. + * + * Only string values are supported for server versions < 4.4. * * * cursorType (enum): Indicates the type of cursor to use. Must be either * NON_TAILABLE, TAILABLE, or TAILABLE_AWAIT. The default is @@ -181,10 +182,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti throw InvalidArgumentException::invalidType('"collation" option', $options['collation'], 'array or object'); } - if (isset($options['comment']) && ! is_string($options['comment'])) { - throw InvalidArgumentException::invalidType('"comment" option', $options['comment'], 'comment'); - } - if (isset($options['cursorType'])) { if (! is_integer($options['cursorType'])) { throw InvalidArgumentException::invalidType('"cursorType" option', $options['cursorType'], 'integer'); diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index c99acc1c7..290b8205f 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -74,6 +74,10 @@ class FindAndModify implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * @@ -298,7 +302,7 @@ private function createCommandDocument() : (object) $this->options['update']; } - foreach (['arrayFilters', 'bypassDocumentValidation', 'hint', 'maxTimeMS'] as $option) { + foreach (['arrayFilters', 'bypassDocumentValidation', 'comment', 'hint', 'maxTimeMS'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index de46314ef..b75edcb1e 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -44,8 +44,9 @@ class FindOne implements Executable, Explainable * * * collation (document): Collation specification. * - * * comment (string): Attaches a comment to the query. If "$comment" also - * exists in the modifiers document, this option will take precedence. + * * comment (mixed): BSON value to attach as a comment to this command. + * + * Only string values are supported for server versions < 4.4. * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 9f27d30d4..03fd6e1a7 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -44,6 +44,10 @@ class FindOneAndDelete implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index 879569bfc..dce8a6a97 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -53,6 +53,10 @@ class FindOneAndReplace implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index 4951f4d0f..98b6cf42c 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -57,6 +57,10 @@ class FindOneAndUpdate implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index 7633905fe..af7bd7361 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -60,6 +60,11 @@ class InsertMany implements Executable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * + * * comment (mixed): BSON value to attach as a comment to the command(s) + * associated with this insert. + * + * This is not supported for servers versions < 4.4. + * * * ordered (boolean): If true, when an insert fails, return without * performing the remaining writes. If false, when a write fails, * continue with the remaining writes, if any. The default is true. @@ -164,8 +169,10 @@ private function createBulkWriteOptions() { $options = ['ordered' => $this->options['ordered']]; - if (isset($this->options['bypassDocumentValidation'])) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + foreach (['bypassDocumentValidation', 'comment'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = $this->options[$option]; + } } return $options; diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index 39e986683..9398f1795 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -59,6 +59,10 @@ class InsertOne implements Executable * * bypassDocumentValidation (boolean): If true, allows the write to * circumvent document level validation. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * session (MongoDB\Driver\Session): Client session. * * * writeConcern (MongoDB\Driver\WriteConcern): Write concern. @@ -135,8 +139,10 @@ private function createBulkWriteOptions() { $options = []; - if (isset($this->options['bypassDocumentValidation'])) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + foreach (['bypassDocumentValidation', 'comment'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = $this->options[$option]; + } } return $options; diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index c5fc568ff..4bc5565a3 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -46,6 +46,10 @@ class ListCollectionNames implements Executable * * For servers < 4.0, this option is ignored. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * filter (document): Query by which to filter collections. * * * maxTimeMS (integer): The maximum amount of time to allow the query to diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php index f346263e3..8a55f9908 100644 --- a/src/Operation/ListCollections.php +++ b/src/Operation/ListCollections.php @@ -49,6 +49,10 @@ class ListCollections implements Executable * * For servers < 4.0, this option is ignored. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * filter (document): Query by which to filter collections. * * * maxTimeMS (integer): The maximum amount of time to allow the query to diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php index 2c15ca97e..950c82b7c 100644 --- a/src/Operation/ListDatabaseNames.php +++ b/src/Operation/ListDatabaseNames.php @@ -49,6 +49,10 @@ class ListDatabaseNames implements Executable * * For servers < 4.0.5, this option is ignored. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * filter (document): Query by which to filter databases. * * * maxTimeMS (integer): The maximum amount of time to allow the query to diff --git a/src/Operation/ListDatabases.php b/src/Operation/ListDatabases.php index abfcb2a0a..6b0c4ba2c 100644 --- a/src/Operation/ListDatabases.php +++ b/src/Operation/ListDatabases.php @@ -47,6 +47,10 @@ class ListDatabases implements Executable * * For servers < 4.0.5, this option is ignored. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * filter (document): Query by which to filter databases. * * * maxTimeMS (integer): The maximum amount of time to allow the query to diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index 213b7dd03..b6e8a1ea0 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -59,6 +59,10 @@ class ListIndexes implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * maxTimeMS (integer): The maximum amount of time to allow the query to * run. * @@ -129,8 +133,10 @@ private function executeCommand(Server $server) { $cmd = ['listIndexes' => $this->collectionName]; - if (isset($this->options['maxTimeMS'])) { - $cmd['maxTimeMS'] = $this->options['maxTimeMS']; + foreach (['comment', 'maxTimeMS'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } try { diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index 46827b1a9..b1e8319ce 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -102,6 +102,10 @@ class MapReduce implements Executable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * finalize (MongoDB\BSON\JavascriptInterface): Follows the reduce method * and modifies the output. * @@ -339,7 +343,7 @@ private function createCommand() 'out' => $this->out, ]; - foreach (['bypassDocumentValidation', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'verbose'] as $option) { + foreach (['bypassDocumentValidation', 'comment', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'verbose'] as $option) { if (isset($this->options[$option])) { $cmd[$option] = $this->options[$option]; } diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php index e6e16961d..cd52cb9a0 100644 --- a/src/Operation/ModifyCollection.php +++ b/src/Operation/ModifyCollection.php @@ -53,6 +53,10 @@ class ModifyCollection implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * session (MongoDB\Driver\Session): Client session. * * * typeMap (array): Type map for BSON deserialization. This will only be @@ -104,7 +108,7 @@ public function __construct($databaseName, $collectionName, array $collectionOpt */ public function execute(Server $server) { - $cursor = $server->executeWriteCommand($this->databaseName, new Command(['collMod' => $this->collectionName] + $this->collectionOptions), $this->createOptions()); + $cursor = $server->executeWriteCommand($this->databaseName, $this->createCommand(), $this->createOptions()); if (isset($this->options['typeMap'])) { $cursor->setTypeMap($this->options['typeMap']); @@ -113,6 +117,17 @@ public function execute(Server $server) return current($cursor->toArray()); } + private function createCommand(): Command + { + $cmd = ['collMod' => $this->collectionName] + $this->collectionOptions; + + if (isset($this->options['comment'])) { + $cmd['comment'] = $this->options['comment']; + } + + return new Command($cmd); + } + /** * Create options for executing the command. * diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php index 1a02cf40f..e489713a3 100644 --- a/src/Operation/RenameCollection.php +++ b/src/Operation/RenameCollection.php @@ -52,6 +52,10 @@ class RenameCollection implements Executable * * Supported options: * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * session (MongoDB\Driver\Session): Client session. * * * typeMap (array): Type map for BSON deserialization. This will be used @@ -112,22 +116,34 @@ public function execute(Server $server) throw UnsupportedException::writeConcernNotSupportedInTransaction(); } + $cursor = $server->executeWriteCommand('admin', $this->createCommand(), $this->createOptions()); + + if (isset($this->options['typeMap'])) { + $cursor->setTypeMap($this->options['typeMap']); + } + + return current($cursor->toArray()); + } + + /** + * Create the renameCollection command. + * + * @return Command + */ + private function createCommand() + { $cmd = [ 'renameCollection' => $this->fromNamespace, 'to' => $this->toNamespace, ]; - if (isset($this->options['dropTarget'])) { - $cmd['dropTarget'] = $this->options['dropTarget']; - } - - $cursor = $server->executeWriteCommand('admin', new Command($cmd), $this->createOptions()); - - if (isset($this->options['typeMap'])) { - $cursor->setTypeMap($this->options['typeMap']); + foreach (['comment', 'dropTarget'] as $option) { + if (isset($this->options[$option])) { + $cmd[$option] = $this->options[$option]; + } } - return current($cursor->toArray()); + return new Command($cmd); } /** diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index 667813775..ef7575ddc 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -50,6 +50,10 @@ class ReplaceOne implements Executable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 5219ce4bb..6ec9a2ac5 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -77,6 +77,10 @@ class Update implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. @@ -243,8 +247,10 @@ private function createBulkWriteOptions() { $options = []; - if (isset($this->options['bypassDocumentValidation'])) { - $options['bypassDocumentValidation'] = $this->options['bypassDocumentValidation']; + foreach (['bypassDocumentValidation', 'comment'] as $option) { + if (isset($this->options[$option])) { + $options[$option] = $this->options[$option]; + } } if (isset($this->options['let'])) { diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index 9db83e629..27a6955ad 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -53,6 +53,10 @@ class UpdateMany implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index ee8a2c32d..22a01e2a0 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -53,6 +53,10 @@ class UpdateOne implements Executable, Explainable * * * collation (document): Collation specification. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * This is not supported for servers versions < 4.4. + * * * hint (string|document): The index to use. Specify either the index * name as a string or the index key pattern as a document. If specified, * then the query system will only consider plans using the hinted index. diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 2e852941a..8de7972fc 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -111,6 +111,10 @@ class Watch implements Executable, /* @internal */ CommandSubscriber * * * collation (document): Specifies a collation. * + * * comment (mixed): BSON value to attach as a comment to this command. + * + * Only string values are supported for server versions < 4.4. + * * * fullDocument (string): Determines how the "fullDocument" response * field will be populated for update operations. * @@ -239,7 +243,7 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } } - $this->aggregateOptions = array_intersect_key($options, ['batchSize' => 1, 'collation' => 1, 'maxAwaitTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1, 'typeMap' => 1]); + $this->aggregateOptions = array_intersect_key($options, ['batchSize' => 1, 'collation' => 1, 'comment' => 1, 'maxAwaitTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1, 'typeMap' => 1]); $this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'fullDocumentBeforeChange' => 1, 'resumeAfter' => 1, 'startAfter' => 1, 'startAtOperationTime' => 1]); // Null database name implies a cluster-wide change stream diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php index 8050f5dd3..db7a62b97 100644 --- a/tests/Operation/AggregateTest.php +++ b/tests/Operation/AggregateTest.php @@ -43,10 +43,6 @@ public function provideInvalidConstructorOptions() $options[][] = ['collation' => $value]; } - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['comment' => $value]; - } - foreach ($this->getInvalidHintValues() as $value) { $options[][] = ['hint' => $value]; } diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php index 3bf09c7bc..c8bc59647 100644 --- a/tests/Operation/FindTest.php +++ b/tests/Operation/FindTest.php @@ -41,10 +41,6 @@ public function provideInvalidConstructorOptions() $options[][] = ['collation' => $value]; } - foreach ($this->getInvalidStringValues() as $value) { - $options[][] = ['comment' => $value]; - } - foreach ($this->getInvalidIntegerValues() as $value) { $options[][] = ['cursorType' => $value]; } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 9fe809ebe..ada9f426d 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -59,58 +59,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType can be set to command and cmap' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType defaults to command if unset' => 'PHPC does not implement CMAP', - // Change stream "comment" option is not yet implemented - 'change-streams/change-streams: Test with document comment' => 'Not yet implemented (PHPLIB-749)', - 'change-streams/change-streams: Test with document comment - pre 4.4' => 'Not yet implemented (PHPLIB-749)', - 'change-streams/change-streams: Test with string comment' => 'Not yet implemented (PHPLIB-749)', - 'change-streams/change-streams: Test that comment is set on getMore' => 'Not yet implemented (PHPLIB-749)', - 'change-streams/change-streams: Test that comment is not set on getMore - pre 4.4' => 'Not yet implemented (PHPLIB-749)', - // CRUD "comment" option is not yet implemented - 'crud/bulkWrite-comment: BulkWrite with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/bulkWrite-comment: BulkWrite with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/bulkWrite-comment: BulkWrite with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/countDocuments-comment: countDocuments with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/countDocuments-comment: countDocuments with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/estimatedDocumentCount-comment: estimatedDocumentCount with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/estimatedDocumentCount-comment: estimatedDocumentCount with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/estimatedDocumentCount-comment: estimatedDocumentCount with document comment - pre 4.4.14, server error' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/deleteMany-comment: deleteMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/deleteMany-comment: deleteMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/deleteMany-comment: deleteMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/deleteOne-comment: deleteOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/deleteOne-comment: deleteOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/deleteOne-comment: deleteOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/find-comment: find with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/find-comment: find with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/find-comment: find with document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/find-comment: find with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndDelete-comment: findOneAndDelete with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndDelete-comment: findOneAndDelete with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndDelete-comment: findOneAndDelete with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndReplace-comment: findOneAndReplace with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndReplace-comment: findOneAndReplace with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndReplace-comment: findOneAndReplace with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndUpdate-comment: findOneAndUpdate with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndUpdate-comment: findOneAndUpdate with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/findOneAndUpdate-comment: findOneAndUpdate with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/insertMany-comment: insertMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/insertMany-comment: insertMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/insertMany-comment: insertMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/insertOne-comment: insertOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/insertOne-comment: insertOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/insertOne-comment: insertOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/replaceOne-comment: ReplaceOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/replaceOne-comment: ReplaceOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/replaceOne-comment: ReplaceOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/updateMany-comment: UpdateMany with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/updateMany-comment: UpdateMany with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/updateMany-comment: UpdateMany with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/updateOne-comment: UpdateOne with string comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/updateOne-comment: UpdateOne with document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/updateOne-comment: UpdateOne with comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/aggregate: aggregate with comment sets comment on getMore' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/aggregate: aggregate with a document comment' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', - 'crud/aggregate: aggregate with a document comment - pre 4.4' => 'Not yet implemented (PHPC-2049, PHPLIB-749)', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 82047934c..0e43addf4 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -72,31 +72,31 @@ final class Util ], Collection::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], - 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation'], - 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'comment'], 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], - 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session'], - 'dropIndex' => ['name', 'session', 'maxTimeMS'], - 'count' => ['filter', 'session', 'collation', 'hint', 'limit', 'maxTimeMS', 'skip'], - 'countDocuments' => ['filter', 'session', 'limit', 'skip', 'collation', 'hint', 'maxTimeMS'], - 'estimatedDocumentCount' => ['session', 'maxTimeMS'], - 'deleteMany' => ['let', 'filter', 'session', 'collation', 'hint'], - 'deleteOne' => ['let', 'filter', 'session', 'collation', 'hint'], - 'findOneAndDelete' => ['let', 'filter', 'session', 'projection', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'sort', 'update', 'upsert'], - 'distinct' => ['fieldName', 'filter', 'session', 'collation', 'maxTimeMS'], - 'drop' => ['session'], + 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session', 'comment'], + 'dropIndex' => ['name', 'session', 'maxTimeMS', 'comment'], + 'count' => ['filter', 'session', 'collation', 'hint', 'limit', 'maxTimeMS', 'skip', 'comment'], + 'countDocuments' => ['filter', 'session', 'limit', 'skip', 'collation', 'hint', 'maxTimeMS', 'comment'], + 'estimatedDocumentCount' => ['session', 'maxTimeMS', 'comment'], + 'deleteMany' => ['let', 'filter', 'session', 'collation', 'hint', 'comment'], + 'deleteOne' => ['let', 'filter', 'session', 'collation', 'hint', 'comment'], + 'findOneAndDelete' => ['let', 'filter', 'session', 'projection', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'sort', 'update', 'upsert', 'comment'], + 'distinct' => ['fieldName', 'filter', 'session', 'collation', 'maxTimeMS', 'comment'], + 'drop' => ['session', 'comment'], 'find' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'findOne' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], - 'findOneAndReplace' => ['let', 'returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort'], - 'rename' => ['to'], - 'replaceOne' => ['let', 'filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], - 'findOneAndUpdate' => ['let', 'returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort'], - 'updateMany' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], - 'updateOne' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint'], - 'insertMany' => ['options', 'documents', 'session', 'ordered', 'bypassDocumentValidation'], - 'insertOne' => ['document', 'session', 'bypassDocumentValidation'], - 'listIndexes' => ['session', 'maxTimeMS'], - 'mapReduce' => ['map', 'reduce', 'out', 'session', 'bypassDocumentValidation', 'collation', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'query', 'scope', 'sort', 'verbose'], + 'findOneAndReplace' => ['let', 'returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort', 'comment'], + 'rename' => ['to', 'comment'], + 'replaceOne' => ['let', 'filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], + 'findOneAndUpdate' => ['let', 'returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort', 'comment'], + 'updateMany' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], + 'updateOne' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], + 'insertMany' => ['options', 'documents', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], + 'insertOne' => ['document', 'session', 'bypassDocumentValidation', 'comment'], + 'listIndexes' => ['session', 'maxTimeMS', 'comment'], + 'mapReduce' => ['map', 'reduce', 'out', 'session', 'bypassDocumentValidation', 'collation', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'query', 'scope', 'sort', 'verbose', 'comment'], ], ChangeStream::class => [ 'iterateUntilDocumentOrError' => [], From bb45c03f33bce4faa38d79fc1eb955ca7d356df6 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 7 Jun 2022 17:03:38 -0400 Subject: [PATCH 165/321] Fix versionadded syntax for autoEncryption driver option --- .../apiargs-MongoDBClient-method-construct-driverOptions.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml b/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml index 5d30540d8..8406bd091 100644 --- a/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-construct-driverOptions.yaml @@ -8,6 +8,7 @@ description: | For the ``keyVaultClient`` option, you may pass a :phpclass:`MongoDB\\Client` instance, which will be unwrapped to provide a :php:`MongoDB\\Driver\\Manager ` to the extension. + .. versionadded:: 1.6 interface: phpmethod operation: ~ From 6bc7fa2c1d25d081c5fcffe4dbe2068ceba5a465 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 8 Jun 2022 17:56:35 -0400 Subject: [PATCH 166/321] PHPLIB-863: Queryable encryption example for docs team (#939) Introduces an isEnterprise() helper, since this example requires automatic encryption. --- tests/DocumentationExamplesTest.php | 108 ++++++++++++++++++++++++++++ tests/FunctionalTestCase.php | 15 ++++ 2 files changed, 123 insertions(+) diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index ffe345d6f..22dddf499 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -2,6 +2,7 @@ namespace MongoDB\Tests; +use MongoDB\BSON\Binary; use MongoDB\BSON\ObjectId; use MongoDB\BSON\UTCDateTime; use MongoDB\Collection; @@ -11,7 +12,9 @@ use MongoDB\Driver\Exception\Exception; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; +use MongoDB\Tests\SpecTests\ClientSideEncryptionSpecTest; +use function base64_decode; use function in_array; use function microtime; use function ob_end_clean; @@ -1848,6 +1851,111 @@ public function testWithTransactionExample(): void // phpcs:enable } + /** + * Queryable encryption examples (not parsed for server manual includes). + * + * @see https://jira.mongodb.org/browse/PHPLIB-863 + * @see ClientSideEncryptionSpecTest::testExplicitEncryption + */ + public function testQueryableEncryption(): void + { + if ($this->isStandalone() || ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets())) { + $this->markTestSkipped('Queryable encryption requires replica sets'); + } + + if (version_compare($this->getServerVersion(), '6.0.0', '<')) { + $this->markTestSkipped('Queryable encryption requires MongoDB 6.0 or later'); + } + + if (! $this->isEnterprise()) { + $this->markTestSkipped('Automatic encryption requires MongoDB Enterprise'); + } + + // Fetch names for the database and collection under test + $collectionName = $this->getCollectionName(); + $databaseName = $this->getDatabaseName(); + $namespace = $this->getNamespace(); + + /* Create a client without auto encryption. Drop existing data in both + * the keyvault and database under test. The latter is necessary since + * setUp() only drops the collection under test, which will leave behind + * internal collections for queryable encryption. */ + $client = static::createTestClient(); + $client->selectDatabase('keyvault')->drop(['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]); + $client->selectDatabase($databaseName)->drop(['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]); + + /* Although ClientEncryption can be constructed directly, the library + * provides a helper to do so. With this method, the keyVaultClient will + * default to the same client. */ + $clientEncryption = $client->createClientEncryption([ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(ClientSideEncryptionSpecTest::LOCAL_MASTERKEY), 0)]], + ]); + + // Create two data keys, one for each encrypted field + $dataKeyId1 = $clientEncryption->createDataKey('local'); + $dataKeyId2 = $clientEncryption->createDataKey('local'); + + $autoEncryptionOpts = [ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(ClientSideEncryptionSpecTest::LOCAL_MASTERKEY), 0)]], + 'encryptedFieldsMap' => [ + $namespace => [ + 'fields' => [ + [ + 'path' => 'encryptedIndexed', + 'bsonType' => 'string', + 'keyId' => $dataKeyId1, + 'queries' => ['queryType' => 'equality'], + ], + [ + 'path' => 'encryptedUnindexed', + 'bsonType' => 'string', + 'keyId' => $dataKeyId2, + ], + ], + ], + ], + ]; + + $encryptedClient = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); + + /* Create the collection under test. The createCollection() helper will + * reference the client's encryptedFieldsMap and create additional, + * internal collections automatically. */ + $encryptedClient->selectDatabase($databaseName)->createCollection($collectionName); + $encryptedCollection = $encryptedClient->selectCollection($databaseName, $collectionName); + + /* Using a client with auto encryption, insert a document with encrypted + * fields and assert that those fields are automatically decrypted when + * querying. */ + $indexedValue = 'indexedValue'; + $unindexedValue = 'unindexedValue'; + + $encryptedCollection->insertOne([ + '_id' => 1, + 'encryptedIndexed' => $indexedValue, + 'encryptedUnindexed' => $unindexedValue, + ]); + + $result = $encryptedCollection->findOne(['encryptedIndexed' => $indexedValue]); + + $this->assertSame(1, $result['_id']); + $this->assertSame($indexedValue, $result['encryptedIndexed']); + $this->assertSame($unindexedValue, $result['encryptedUnindexed']); + + /* Using a client without auto encryption, query for the same + * document and assert that encrypted data is returned. */ + $unencryptedClient = static::createTestClient(); + $unencryptedCollection = $unencryptedClient->selectCollection($databaseName, $collectionName); + + $result = $unencryptedCollection->findOne(['_id' => 1]); + + $this->assertSame(1, $result['_id']); + $this->assertInstanceOf(Binary::class, $result['encryptedIndexed']); + $this->assertInstanceOf(Binary::class, $result['encryptedUnindexed']); + } + /** * Return the test collection name. * diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index c97474cee..dcab12d36 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -28,6 +28,7 @@ use function filter_var; use function getenv; use function implode; +use function in_array; use function is_array; use function is_callable; use function is_object; @@ -376,6 +377,20 @@ protected function getServerStorageEngine(?ReadPreference $readPreference = null throw new UnexpectedValueException('Could not determine server storage engine'); } + protected function isEnterprise(): bool + { + $buildInfo = $this->getPrimaryServer()->executeCommand( + $this->getDatabaseName(), + new Command(['buildInfo' => 1]) + )->toArray()[0]; + + if (isset($buildInfo->modules) && is_array($buildInfo->modules)) { + return in_array('enterprise', $buildInfo->modules); + } + + throw new UnexpectedValueException('Could not determine server modules'); + } + protected function isLoadBalanced() { return $this->getPrimaryServer()->getType() == Server::TYPE_LOAD_BALANCER; From e5b70b910380f15acb1cc52e89afcfc48bef122d Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Thu, 9 Jun 2022 23:41:44 +0300 Subject: [PATCH 167/321] PHPLIB-880: Add comment option tests for distinct helper (#940) Synced with mongodb/specifications@ba44473e2488290e13acabbea0f32fa8c2bc4b7a --- .../crud/distinct-comment.json | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 tests/UnifiedSpecTests/crud/distinct-comment.json diff --git a/tests/UnifiedSpecTests/crud/distinct-comment.json b/tests/UnifiedSpecTests/crud/distinct-comment.json new file mode 100644 index 000000000..0669d4f30 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/distinct-comment.json @@ -0,0 +1,178 @@ +{ + "description": "distinct-comment", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "distinct-comment-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "distinct-comment-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3, + "x": 33 + } + ] + } + ], + "tests": [ + { + "description": "distinct with document comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4.14" + } + ], + "operations": [ + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "comment": { + "key": "value" + } + }, + "expectResult": [ 11, 22, 33 ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "coll0", + "key": "x", + "query": {}, + "comment": { + "key": "value" + } + }, + "commandName": "distinct", + "databaseName": "distinct-comment-tests" + } + } + ] + } + ] + }, + { + "description": "distinct with string comment", + "runOnRequirements": [ + { + "minServerVersion": "4.4.0" + } + ], + "operations": [ + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "comment": "comment" + }, + "expectResult": [ 11, 22, 33 ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "coll0", + "key": "x", + "query": {}, + "comment": "comment" + }, + "commandName": "distinct", + "databaseName": "distinct-comment-tests" + } + } + ] + } + ] + }, + { + "description": "distinct with document comment - pre 4.4, server error", + "runOnRequirements": [ + { + "minServerVersion": "3.6.0", + "maxServerVersion": "4.4.13" + } + ], + "operations": [ + { + "name": "distinct", + "object": "collection0", + "arguments": { + "fieldName": "x", + "filter": {}, + "comment": { + "key": "value" + } + }, + "expectError": { + "isClientError": false + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "distinct": "coll0", + "key": "x", + "query": {}, + "comment": { + "key": "value" + } + }, + "commandName": "distinct", + "databaseName": "distinct-comment-tests" + } + } + ] + } + ] + } + ] +} From af419eb8869a0903f5388f20d1891f287c491903 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 13 Jun 2022 16:47:20 -0400 Subject: [PATCH 168/321] PHPLIB-885: Bypass spawning mongocryptd with bypassQueryAnalysis (#942) --- .../ClientSideEncryptionSpecTest.php | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index ee0860a89..93fa5944c 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -873,7 +873,35 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); - $clientEncrypted->selectCollection('db', 'coll')->insertOne(['encrypted' => 'test']); + $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']); + + $clientMongocryptd = static::createTestClient('mongodb://localhost:27021'); + + $this->expectException(ConnectionTimeoutException::class); + $clientMongocryptd->selectDatabase('db')->command(['ping' => 1]); + } + + /** + * Prose test 8: Bypass spawning mongocryptd (via bypassQueryAnalysis) + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#via-bypassqueryanalysis + */ + public function testBypassSpawningMongocryptdViaBypassQueryAnalysis(): void + { + $autoEncryptionOpts = [ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], + ], + 'bypassQueryAnalysis' => true, + 'extraOptions' => [ + 'mongocryptdSpawnArgs' => ['--pidfilepath=bypass-spawning-mongocryptd.pid', '--port=27021'], + ], + ]; + + $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); + + $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']); $clientMongocryptd = static::createTestClient('mongodb://localhost:27021'); From 809223b183e0ca35fcb2e6c0915f376ebe65d7de Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 20 Jun 2022 17:01:39 -0400 Subject: [PATCH 169/321] PHPLIB-858: Test against MongoDB 6.0 in Evergreen and revise matrices (#944) Update axes definitions: * Add "mongodb" to version and edge-version axes names * Add MongoDB 6.0 to mongodb-versions matrix * Add PHP 8.1 to php-versions matrix * Bump latest-stable in php-edge-versions to PHP 8.1 * Add Debian 11 and 10 to OS matrix * Make alt arch operating systems consistent with PHPC Revise test matrices to prefer Debian 11 when possible. --- .evergreen/config.yml | 133 ++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 62 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 2ef003753..32b7afa02 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -516,20 +516,24 @@ axes: - id: php-versions display_name: PHP Version values: + - id: "8.1" + display_name: "PHP 8.1" + variables: + PHP_VERSION: "8.1" - id: "8.0" - display_name: "8.0" + display_name: "PHP 8.0" variables: PHP_VERSION: "8.0" - id: "7.4" - display_name: "7.4" + display_name: "PHP 7.4" variables: PHP_VERSION: "7.4" - id: "7.3" - display_name: "7.3" + display_name: "PHP 7.3" variables: PHP_VERSION: "7.3" - id: "7.2" - display_name: "7.2" + display_name: "PHP 7.2" variables: PHP_VERSION: "7.2" @@ -537,51 +541,55 @@ axes: display_name: PHP Version values: - id: "latest-stable" - display_name: "8.0" + display_name: "PHP 8.1" variables: - PHP_VERSION: "8.0" + PHP_VERSION: "8.1" - id: "oldest-supported" - display_name: "7.2" + display_name: "PHP 7.2" variables: PHP_VERSION: "7.2" - - id: versions + - id: mongodb-versions display_name: MongoDB Version values: - id: "latest" - display_name: "latest" + display_name: "MongoDB latest" variables: VERSION: "latest" + - id: "6.0" + display_name: "MongoDB 6.0" + variables: + VERSION: "6.0" - id: "5.0" - display_name: "5.0" + display_name: "MongoDB 5.0" variables: VERSION: "5.0" - id: "4.4" - display_name: "4.4" + display_name: "MongoDB 4.4" variables: VERSION: "4.4" - id: "4.2" - display_name: "4.2" + display_name: "MongoDB 4.2" variables: VERSION: "4.2" - id: "4.0" - display_name: "4.0" + display_name: "MongoDB 4.0" variables: VERSION: "4.0" - id: "3.6" - display_name: "3.6" + display_name: "MongoDB 3.6" variables: VERSION: "3.6" - - id: edge-versions + - id: mongodb-edge-versions display_name: MongoDB Version values: - id: "latest-stable" - display_name: "5.0" + display_name: "MongoDB 5.0" variables: VERSION: "5.0" - id: "oldest-supported" - display_name: "3.6" + display_name: "MongoDB 3.6" variables: VERSION: "3.6" @@ -591,39 +599,45 @@ axes: # TODO: Update to "1.14.0" once PHPC 1.14.0 is released - id: "oldest-supported" # display_name: "1.14.0" - display_name: "1.14-dev (master)" + display_name: "PHPC 1.14-dev (master)" variables: # EXTENSION_VERSION: "1.14.0" EXTENSION_BRANCH: "master" # TODO: Update to "1.14.x"/"stable" once PHPC 1.14.0 is released - id: "latest-stable" # display_name: "1.14.x" - display_name: "1.14-dev (master)" + display_name: "PHPC 1.14-dev (master)" variables: # EXTENSION_VERSION: "stable" EXTENSION_BRANCH: "master" - id: "latest-dev" - display_name: "1.14-dev (master)" + display_name: "PHPC 1.14-dev (master)" variables: EXTENSION_BRANCH: "master" - id: os display_name: OS values: - - id: debian92-test - display_name: "Debian 9.2" - run_on: debian92-test - - id: rhel70-test - display_name: "RHEL 7.0" + - id: debian11 + display_name: "Debian 11" + run_on: debian11 + - id: debian10 + display_name: "Debian 10" + run_on: debian10 + - id: debian92 + display_name: "Debian 9.2" + run_on: debian92 + - id: rhel70 + display_name: "RHEL 7.0" run_on: rhel70 - id: rhel71-power8 - display_name: "RHEL 7.1 Power 8" - run_on: rhel71-power8-test - - id: rhel74-zseries - display_name: "RHEL 7.4 zSeries" - run_on: rhel74-zseries-test - - id: ubuntu1804-arm64-test - display_name: "Ubuntu 18.04 ARM64" + display_name: "RHEL 7.1 Power 8" + run_on: rhel71-power8-build + - id: rhel72-zseries + display_name: "RHEL 7.2 zSeries" + run_on: rhel72-zseries-build + - id: ubuntu1804-arm64 + display_name: "Ubuntu 18.04 ARM64" run_on: ubuntu1804-arm64-test - id: topology @@ -691,40 +705,35 @@ axes: DEPENDENCIES: "lowest" buildvariants: - -# Tests all PHP versions on all operating systems and latest MongoDB and ext-mongodb versions +# Test all PHP versions with latest-stable MongoDB and PHPC on Debian - matrix_name: "test-php-versions" - matrix_spec: { "os": "*", "edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-stable" } + matrix_spec: { "os": "debian11", "mongodb-edge-versions": "latest-stable", "php-versions": "*", "driver-versions": "latest-stable" } + display_name: "${os}, ${mongodb-edge-versions}, ${php-versions}, ${driver-versions}" exclude_spec: - # rhel71-power8 fails due to not reaching pecl - - { "os": "rhel71-power8", "edge-versions": "*", "php-versions": "*", "driver-versions": "*" } - # rhel74-zseries doesn't start in a timely fashion - most likely missing executors - - { "os": "rhel74-zseries", "edge-versions": "*", "php-versions": "*", "driver-versions": "*" } - # rhel70 does not have PHP 8.0 - - { "os": "rhel70-test", "edge-versions": "*", "php-versions": "8.0", "driver-versions": "*" } - display_name: "${os}, MongoDB ${edge-versions}, PHP ${php-versions}, ext-mongodb ${driver-versions}" + # Exclude "latest-stable" PHP version for Debian 11 (see: test-mongodb-versions matrix) + - { "os": "debian11", "mongodb-edge-versions": "latest-stable", "php-versions": "8.1", "driver-versions": "latest-stable" } tasks: - name: "test-standalone" - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests all MongoDB versions with latest stable PHP and driver versions +# Test all topologies and MongoDB versions with latest-stable PHP and PHPC on Debian - matrix_name: "test-mongodb-versions" - matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + matrix_spec: { "os": ["debian92", "debian11"], "mongodb-versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "${os}, ${mongodb-versions}, ${php-edge-versions}, ${driver-versions}" exclude_spec: - # Avoid duplicate build variants from test-php-versions (assumes edge-versions:latest-stable is 5.0) - - { "os": "debian92-test", "versions": "5.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } - display_name: "${os}, MongoDB ${versions}, PHP ${php-edge-versions}, ext-mongodb ${driver-versions}" + # Debian 9.2 only supports up to MongoDB 5.0 + - { "os": "debian92", "mongodb-versions": ["6.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4", "5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } tasks: - name: "test-standalone" - name: "test-replica_set" - name: "test-sharded_cluster" -# Tests all MongoDB versions with oldest supported PHP and driver versions -# Enables --prefer-lowest for composer to test oldest dependencies against all server versions -- matrix_name: "test-dependencies" - matrix_spec: { "os": "debian92-test", "versions": "*", "php-edge-versions": "oldest-supported", "driver-versions": "oldest-supported", "dependencies": "lowest" } - display_name: "Lowest Dependencies: ${os}, MongoDB ${versions}, PHP ${php-edge-versions}, ext-mongodb ${driver-versions}" +# Test oldest-supported PHP, MongoDB, and driver versions with lowest dependencies on Debian +- matrix_name: "test-oldest-supported" + matrix_spec: { "os": "debian92", "mongodb-edge-versions": "oldest-supported", "php-edge-versions": "oldest-supported", "driver-versions": "oldest-supported", "dependencies": "lowest" } + display_name: "Lowest Dependencies: ${os}, ${mongodb-edge-versions}, ${php-edge-versions}, ${driver-versions}" tasks: - name: "test-standalone" - name: "test-replica_set" @@ -733,27 +742,27 @@ buildvariants: - matrix_name: "atlas-data-lake-test" matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Atlas Data Lake" - run_on: debian92-test + run_on: debian11 tasks: - name: "test-atlas-data-lake" -- matrix_name: "test-versioned-api" - matrix_spec: { "versions": ["5.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } - display_name: "Versioned API - ${versions}" - run_on: debian92-test +# Stable API is available from MongoDB 5.0+ +- matrix_name: "test-requireApiVersion" + matrix_spec: { "os": "debian11", "mongodb-versions": ["5.0", "6.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "Versioned API - ${mongodb-versions}" tasks: - .versioned-api - matrix_name: "serverless" - matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + matrix_spec: { "os": "debian11", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Serverless" - run_on: debian92-test tasks: - .serverless +# Load balancer is available from MongoDB 5.0+ - matrix_name: "test-loadBalanced" - matrix_spec: { "versions": ["5.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } - display_name: "Load balanced - ${versions}" - run_on: debian92-test + # TODO: Add MongoDB 6.0 and use Debian 11 once BUILD-15237 is resolved + matrix_spec: { "os": "debian92", "mongodb-versions": ["5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "Load balanced - ${mongodb-versions}" tasks: - name: "test-loadBalanced" From 265810afc9c19247fded2d5530793ef1a91bf340 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 23 Jun 2022 14:02:58 -0400 Subject: [PATCH 170/321] PHPLIB-891: Run CSFLE tests with crypt_shared (#943) * Ensure TESTS var is passed through to run-tests.sh This likely dates back to d1b18dd51dad81eea60ab7b71a7bcc0c0190845e --- .evergreen/config.yml | 34 +++++++++++- .evergreen/run-tests.sh | 4 ++ .../ClientSideEncryptionSpecTest.php | 52 +++++++++++++++++-- tests/SpecTests/Context.php | 5 ++ 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 32b7afa02..69333d384 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -246,8 +246,9 @@ functions: export KMS_ENDPOINT_REQUIRE_CLIENT_CERT="${client_side_encryption_kms_endpoint_require_client_cert}" export KMS_TLS_CA_FILE="${client_side_encryption_kms_tls_ca_file}" export KMS_TLS_CERTIFICATE_KEY_FILE="${client_side_encryption_kms_tls_certificate_key_file}" + export CRYPT_SHARED_LIB_PATH="${client_side_encryption_crypt_shared_lib_path}" export PATH="${PHP_PATH}/bin:$PATH" - API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} TESTS=${TESTS} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run atlas data lake test": - command: shell.exec @@ -377,6 +378,18 @@ functions: - key: client_side_encryption_kmip_endpoint value: localhost:5698 + "fetch crypt_shared": + - command: shell.exec + params: + script: | + # TODO: Specify same version provisioned by download-mongodb.sh (see: DRIVERS-2355) + python3 ${DRIVERS_TOOLS}/.evergreen/mongodl.py --component crypt_shared --version latest --only "**/mongo_crypt_v1.so" --out ${DRIVERS_TOOLS}/.evergreen/csfle --strip-path-components 1 + - command: expansions.update + params: + updates: + - key: client_side_encryption_crypt_shared_lib_path + value: ${DRIVERS_TOOLS}/.evergreen/csfle/mongo_crypt_v1.so + pre: - func: "fetch source" - func: "prepare resources" @@ -507,6 +520,18 @@ tasks: MONGODB_URI: "${SINGLE_MONGOS_LB_URI}" SSL: "yes" # Note: "stop load balancer" will be called from "post" + + - name: "test-crypt_shared" + commands: + - func: "bootstrap mongo-orchestration" + vars: + TOPOLOGY: "replica_set" + - func: "start kms servers" + - func: "fetch crypt_shared" + - func: "run tests" + vars: + TESTS: "csfle" + # }}} @@ -766,3 +791,10 @@ buildvariants: display_name: "Load balanced - ${mongodb-versions}" tasks: - name: "test-loadBalanced" + +# CSFLE crypt_shared is available from MongoDB 6.0+ +- matrix_name: "test-csfle-crypt_shared" + matrix_spec: { "os": "debian11", "mongodb-versions": "6.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "CSFLE crypt_shared - ${mongodb-versions}" + tasks: + - name: "test-crypt_shared" diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 82c01c461..9cc49ff0c 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -67,6 +67,10 @@ case "$TESTS" in php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --testsuite "Atlas Data Lake Test Suite" $PHPUNIT_OPTS ;; + csfle) + php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group csfle $PHPUNIT_OPTS + ;; + versioned-api) php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group versioned-api $PHPUNIT_OPTS ;; diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 93fa5944c..c28c3cdd7 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -31,6 +31,7 @@ use function glob; use function in_array; use function is_executable; +use function is_readable; use function iterator_to_array; use function json_decode; use function sprintf; @@ -46,6 +47,7 @@ * Client-side encryption spec tests. * * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption + * @group csfle */ class ClientSideEncryptionSpecTest extends FunctionalTestCase { @@ -65,7 +67,10 @@ public function setUp(): void parent::setUp(); $this->skipIfClientSideEncryptionIsNotSupported(); - $this->skipIfLocalMongocryptdIsUnavailable(); + + if (! static::isCryptSharedLibAvailable() && ! static::isMongocryptdAvailable()) { + $this->markTestSkipped('Neither crypt_shared nor mongocryptd are available'); + } } /** @@ -79,6 +84,15 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual static::assertDocumentsMatch($expected, $actual); } + public static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client + { + if (isset($driverOptions['autoEncryption']) && getenv('CRYPT_SHARED_LIB_PATH')) { + $driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'] = getenv('CRYPT_SHARED_LIB_PATH'); + } + + return parent::createTestClient($uri, $options, $driverOptions); + } + /** * Execute an individual test case from the specification. * @@ -825,6 +839,14 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio */ public function testBypassSpawningMongocryptdViaBypassSpawn(): void { + /* If crypt_shared is available it will likely already have been loaded + * by a previous test so there is no way to prevent it from being used. + * Since CSFLE prefers crypt_shared to mongocryptd there is reason to + * run any of the "bypass spawning" tests (see also: MONGOCRYPT-421). */ + if (static::isCryptSharedLibAvailable()) { + $this->markTestSkipped('Bypass spawning of mongocryptd cannot be tested when crypt_shared is available'); + } + $autoEncryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ @@ -840,6 +862,7 @@ public function testBypassSpawningMongocryptdViaBypassSpawn(): void ], ]; + // Disable adding cryptSharedLibPath, as it may interfere with this test $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); try { @@ -860,6 +883,10 @@ public function testBypassSpawningMongocryptdViaBypassSpawn(): void */ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void { + if (static::isCryptSharedLibAvailable()) { + $this->markTestSkipped('Bypass spawning of mongocryptd cannot be tested when crypt_shared is available'); + } + $autoEncryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ @@ -871,6 +898,7 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void ], ]; + // Disable adding cryptSharedLibPath, as it may interfere with this test $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']); @@ -888,6 +916,10 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void */ public function testBypassSpawningMongocryptdViaBypassQueryAnalysis(): void { + if (static::isCryptSharedLibAvailable()) { + $this->markTestSkipped('Bypass spawning of mongocryptd cannot be tested when crypt_shared is available'); + } + $autoEncryptionOpts = [ 'keyVaultNamespace' => 'keyvault.datakeys', 'kmsProviders' => [ @@ -899,6 +931,7 @@ public function testBypassSpawningMongocryptdViaBypassQueryAnalysis(): void ], ]; + // Disable adding cryptSharedLibPath, as it may interfere with this test $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]); $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']); @@ -1525,16 +1558,27 @@ private function prepareEncryptedFieldsMap(stdClass $encryptedFieldsMap): stdCla return $encryptedFieldsMap; } - private function skipIfLocalMongocryptdIsUnavailable(): void + private static function isCryptSharedLibAvailable(): bool + { + $cryptSharedLibPath = getenv('CRYPT_SHARED_LIB_PATH'); + + if ($cryptSharedLibPath === false) { + return false; + } + + return is_readable($cryptSharedLibPath); + } + + private static function isMongocryptdAvailable(): bool { $paths = explode(PATH_SEPARATOR, getenv("PATH")); foreach ($paths as $path) { if (is_executable($path . DIRECTORY_SEPARATOR . 'mongocryptd')) { - return; + return true; } } - $this->markTestSkipped('Mongocryptd is not available on the localhost'); + return false; } } diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 6f1fc55d7..fbc55ae31 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -107,6 +107,11 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ $autoEncryptionOptions['tlsOptions']->kmip = self::getKmsTlsOptions(); } + + // Intentionally ignore empty values for CRYPT_SHARED_LIB_PATH + if (getenv('CRYPT_SHARED_LIB_PATH')) { + $autoEncryptionOptions['extraOptions']['cryptSharedLibPath'] = getenv('CRYPT_SHARED_LIB_PATH'); + } } if (isset($test->outcome->collection->name)) { From a495bf5369f08048b5467803d9abdec35edac2bb Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 23 Jun 2022 16:15:48 -0400 Subject: [PATCH 171/321] PHPLIB-884: Remove manual preparation of "contention" option (#945) The necessary fix is included in MongoDB 6.0.0-rc10. --- .../ClientSideEncryptionSpecTest.php | 34 ++----------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index c28c3cdd7..1360e0b5e 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -124,7 +124,7 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d // TODO: Remove this once SERVER-66901 is implemented (see: PHPLIB-884) if (isset($test->clientOptions->autoEncryptOpts->encryptedFieldsMap)) { - $test->clientOptions->autoEncryptOpts->encryptedFieldsMap = $this->prepareEncryptedFieldsMap($test->clientOptions->autoEncryptOpts->encryptedFieldsMap); + $test->clientOptions->autoEncryptOpts->encryptedFieldsMap = $test->clientOptions->autoEncryptOpts->encryptedFieldsMap; } try { @@ -1233,7 +1233,7 @@ public function testExplicitEncryption(Closure $test): void } // Test setup - $encryptedFields = $this->prepareEncryptedFields($this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/encryptedFields.json'))); + $encryptedFields = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/encryptedFields.json')); $key1Document = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/keys/key1-document.json')); $key1Id = $key1Document->_id; @@ -1407,7 +1407,7 @@ private function createTestCollection(?stdClass $encryptedFields = null, ?stdCla $options = $context->defaultWriteOptions; if (! empty($encryptedFields)) { - $options['encryptedFields'] = $this->prepareEncryptedFields($encryptedFields); + $options['encryptedFields'] = $encryptedFields; } if (! empty($jsonSchema)) { @@ -1530,34 +1530,6 @@ private function prepareCorpusData(string $fieldName, stdClass $data, ClientEncr return $data->allowed ? $returnData : $data; } - /** - * @todo Remove this once SERVER-66901 is implemented - * @see https://jira.mongodb.org/browse/PHPLIB-884 - */ - private function prepareEncryptedFields(stdClass $encryptedFields): stdClass - { - foreach ($encryptedFields->fields as $field) { - if (isset($field->queries->contention)) { - $field->queries->contention = $this->createInt64($field->queries->contention); - } - } - - return $encryptedFields; - } - - /** - * @todo Remove this once SERVER-66901 is implemented - * @see https://jira.mongodb.org/browse/PHPLIB-884 - */ - private function prepareEncryptedFieldsMap(stdClass $encryptedFieldsMap): stdClass - { - foreach ($encryptedFieldsMap as $namespace => $encryptedFields) { - $encryptedFieldsMap->{$namespace} = $this->prepareEncryptedFields($encryptedFields); - } - - return $encryptedFieldsMap; - } - private static function isCryptSharedLibAvailable(): bool { $cryptSharedLibPath = getenv('CRYPT_SHARED_LIB_PATH'); From ca6a034e5055a8d299f85bbeaba7967abd8b2401 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 27 Jun 2022 13:28:20 -0400 Subject: [PATCH 172/321] PHPLIB-890: Test auto decryption occurs after CommandSucceeded events (#946) --- .../ClientSideEncryptionSpecTest.php | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 1360e0b5e..5d028d942 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -10,10 +10,15 @@ use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Exception\AuthenticationException; use MongoDB\Driver\Exception\BulkWriteException; +use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\Exception\ConnectionException; use MongoDB\Driver\Exception\ConnectionTimeoutException; use MongoDB\Driver\Exception\EncryptionException; use MongoDB\Driver\Exception\RuntimeException; +use MongoDB\Driver\Monitoring\CommandFailedEvent; +use MongoDB\Driver\Monitoring\CommandStartedEvent; +use MongoDB\Driver\Monitoring\CommandSubscriber; +use MongoDB\Driver\Monitoring\CommandSucceededEvent; use MongoDB\Driver\WriteConcern; use MongoDB\Tests\CommandObserver; use PHPUnit\Framework\Assert; @@ -37,6 +42,7 @@ use function sprintf; use function str_repeat; use function strlen; +use function substr; use function unserialize; use function version_compare; @@ -1393,6 +1399,155 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt ]; } + /** + * Prose test 14: Decryption Events + * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#decryption-events + * @dataProvider provideDecryptionEventsTests + */ + public function testDecryptionEvents(Closure $test): void + { + // Test setup + $setupClient = static::createTestClient(); + $setupClient->selectCollection('db', 'decryption_events')->drop(); + + // Ensure that the key vault is dropped with a majority write concern + self::insertKeyVaultData($setupClient, []); + + $clientEncryption = new ClientEncryption([ + 'keyVaultClient' => $setupClient->getManager(), + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]], + ]); + + $keyId = $clientEncryption->createDataKey('local'); + + $cipherText = $clientEncryption->encrypt('hello', [ + 'keyId' => $keyId, + 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, + ]); + + // Flip the last byte in the encrypted string + $malformedCipherText = new Binary(substr($cipherText->getData(), 0, -1) . ~$cipherText->getData()[-1], Binary::TYPE_ENCRYPTED); + + $autoEncryptionOpts = [ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]], + ]; + + $encryptedClient = static::createTestClient(null, ['retryReads' => false], ['autoEncryption' => $autoEncryptionOpts]); + + $subscriber = new class implements CommandSubscriber { + public $lastAggregateReply; + public $lastAggregateError; + + public function commandStarted(CommandStartedEvent $event): void + { + } + + public function commandSucceeded(CommandSucceededEvent $event): void + { + if ($event->getCommandName() === 'aggregate') { + $this->lastAggregateReply = $event->getReply(); + } + } + + public function commandFailed(CommandFailedEvent $event): void + { + if ($event->getCommandName() === 'aggregate') { + $this->lastAggregateError = $event->getError(); + } + } + }; + + $encryptedClient->getManager()->addSubscriber($subscriber); + + $test($this, $setupClient, $clientEncryption, $encryptedClient, $subscriber, $cipherText, $malformedCipherText); + + $encryptedClient->getManager()->removeSubscriber($subscriber); + } + + public static function provideDecryptionEventsTests() + { + // See: https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#case-1-command-error + yield 'Case 1: Command Error' => [ + static function (self $test, Client $setupClient, ClientEncryption $clientEncryption, Client $encryptedClient, CommandSubscriber $subscriber, Binary $cipherText, Binary $malformedCipherText): void { + $setupClient->selectDatabase('admin')->command([ + 'configureFailPoint' => 'failCommand', + 'mode' => ['times' => 1], + 'data' => [ + 'errorCode' => 123, + 'failCommands' => ['aggregate'], + ], + ]); + + try { + $encryptedClient->selectCollection('db', 'decryption_events')->aggregate([]); + $test->fail('Expected exception to be thrown'); + } catch (CommandException $e) { + $test->assertSame(123, $e->getCode()); + } + + $test->assertNotNull($subscriber->lastAggregateError); + }, + ]; + + // See: https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#case-2-network-error + yield 'Case 2: Network Error' => [ + static function (self $test, Client $setupClient, ClientEncryption $clientEncryption, Client $encryptedClient, CommandSubscriber $subscriber, Binary $cipherText, Binary $malformedCipherText): void { + $setupClient->selectDatabase('admin')->command([ + 'configureFailPoint' => 'failCommand', + 'mode' => ['times' => 1], + 'data' => [ + 'closeConnection' => true, + 'failCommands' => ['aggregate'], + ], + ]); + + try { + $encryptedClient->selectCollection('db', 'decryption_events')->aggregate([]); + $test->fail('Expected exception to be thrown'); + } catch (ConnectionTimeoutException $e) { + $test->addToAssertionCount(1); + } + + $test->assertNotNull($subscriber->lastAggregateError); + }, + ]; + + // See: https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#case-3-decrypt-error + yield 'Case 3: Decrypt Error' => [ + static function (self $test, Client $setupClient, ClientEncryption $clientEncryption, Client $encryptedClient, CommandSubscriber $subscriber, Binary $cipherText, Binary $malformedCipherText): void { + $collection = $encryptedClient->selectCollection('db', 'decryption_events'); + + $collection->insertOne(['encrypted' => $malformedCipherText]); + + try { + $collection->aggregate([]); + $test->fail('Expected exception to be thrown'); + } catch (EncryptionException $e) { + $test->assertStringContainsString('HMAC validation failure', $e->getMessage()); + } + + $test->assertNotNull($subscriber->lastAggregateReply); + $test->assertEquals($malformedCipherText, $subscriber->lastAggregateReply->cursor->firstBatch[0]->encrypted ?? null); + }, + ]; + + // See: https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#case-4-decrypt-success + yield 'Case 4: Decrypt Success' => [ + static function (self $test, Client $setupClient, ClientEncryption $clientEncryption, Client $encryptedClient, CommandSubscriber $subscriber, Binary $cipherText, Binary $malformedCipherText): void { + $collection = $encryptedClient->selectCollection('db', 'decryption_events'); + + $collection->insertOne(['encrypted' => $cipherText]); + $collection->aggregate([]); + + $test->assertNotNull($subscriber->lastAggregateReply); + $test->assertEquals($cipherText, $subscriber->lastAggregateReply->cursor->firstBatch[0]->encrypted ?? null); + }, + ]; + } + private function createInt64(string $value): Int64 { $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value); From 225dd31e9bb0b05027f25601df28a6a937a977f9 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Thu, 7 Jul 2022 18:18:46 +0300 Subject: [PATCH 173/321] PHPLIB-900: Spec test for discarding dirty implicit session incorrectly uses explicit session Synced with mongodb/specifications@c8699ad --- .../sessions/driver-sessions-dirty-session-errors.json | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json b/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json index 88a9171db..361ea83d7 100644 --- a/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json +++ b/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json @@ -448,7 +448,6 @@ "name": "insertOne", "object": "collection0", "arguments": { - "session": "session0", "document": { "_id": 2 } From b566bcaa20d17a6f0f2396c86e847b6591f877be Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 7 Jul 2022 11:26:22 -0400 Subject: [PATCH 174/321] PHPLIB-810: Update version check for stable API count test (#950) MongoDB 6.0 added the count command to API version 1 and that change was later backported to 5.0.9 and 5.3.2. --- tests/DocumentationExamplesTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 22dddf499..23ac8b50f 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1726,8 +1726,8 @@ public function testVersionedApiMigration(): void $this->markTestSkipped('Versioned API is not supported'); } - if (version_compare($this->getServerVersion(), '5.9', '>=')) { - $this->markTestIncomplete('SERVER-63850 added count command to API version 1 in MongoDB 6.0.0-rc0 (see: PHPLIB-810)'); + if (version_compare($this->getServerVersion(), '5.0.9', '>=')) { + $this->markTestSkipped('The count command was added to API version 1 (SERVER-63850)'); } $uriString = static::getUri(true); From 8d94d8daa767e16f8bea7d6f64f0280a1912f226 Mon Sep 17 00:00:00 2001 From: Aleksandr Rudo Date: Thu, 7 Jul 2022 20:22:16 +0300 Subject: [PATCH 175/321] PHPLIB-846: Improved change stream event visibility for C2C Replication (#949) Spec tests synced with mongodb/specifications@8da1a8990611687cfc9217322f90df47b047726a Co-authored-by: Jeremy Mikola --- ...rgs-MongoDBClient-method-watch-option.yaml | 6 + ...MongoDBCollection-method-watch-option.yaml | 6 + ...s-MongoDBDatabase-method-watch-option.yaml | 6 + .../includes/apiargs-method-watch-option.yaml | 25 + src/Operation/Watch.php | 12 +- tests/UnifiedSpecTests/Operation.php | 6 +- tests/UnifiedSpecTests/Util.php | 8 +- .../change-streams-showExpandedEvents.json | 509 ++++++++++++++++++ 8 files changed, 572 insertions(+), 6 deletions(-) create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json diff --git a/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml b/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml index 96d11eacb..cad9c3f75 100644 --- a/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBClient-method-watch-option.yaml @@ -49,6 +49,12 @@ source: file: apiargs-common-option.yaml ref: session --- +source: + file: apiargs-method-watch-option.yaml + ref: showExpandedEvents +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: startAfter diff --git a/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml b/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml index d1c426229..0a47ae623 100644 --- a/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBCollection-method-watch-option.yaml @@ -49,6 +49,12 @@ source: file: apiargs-common-option.yaml ref: session --- +source: + file: apiargs-method-watch-option.yaml + ref: showExpandedEvents +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: startAfter diff --git a/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml index 3ee3c1446..b24efbec2 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-watch-option.yaml @@ -49,6 +49,12 @@ source: file: apiargs-common-option.yaml ref: session --- +source: + file: apiargs-method-watch-option.yaml + ref: showExpandedEvents +post: | + .. versionadded:: 1.13 +--- source: file: apiargs-method-watch-option.yaml ref: startAfter diff --git a/docs/includes/apiargs-method-watch-option.yaml b/docs/includes/apiargs-method-watch-option.yaml index 00aba3135..01b7f7659 100644 --- a/docs/includes/apiargs-method-watch-option.yaml +++ b/docs/includes/apiargs-method-watch-option.yaml @@ -97,6 +97,31 @@ operation: ~ optional: true --- arg_name: option +name: showExpandedEvents +type: boolean +description: | + If true, instructs the server to include additional DDL events in the change + stream. The additional events that may be included are: + + - ``createIndexes`` + - ``dropIndexes`` + - ``modify`` + - ``create`` + - ``shardCollection`` + - ``reshardCollection`` (server 6.1+) + - ``refineCollectionShardKey`` (server 6.1+) + + This is not supported for server versions prior to 6.0 and will result in an + exception at execution time if used. + + .. note:: + + This is an option of the ``$changeStream`` pipeline stage. +interface: phpmethod +operation: ~ +optional: true +--- +arg_name: option name: startAfter type: array|object description: | diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 8de7972fc..7c0ebea04 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -38,6 +38,7 @@ use function array_unshift; use function count; use function is_array; +use function is_bool; use function is_object; use function is_string; use function MongoDB\Driver\Monitoring\addSubscriber; @@ -161,6 +162,11 @@ class Watch implements Executable, /* @internal */ CommandSubscriber * * * session (MongoDB\Driver\Session): Client session. * + * * showExpandedEvents (boolean): Enables the server to send the expanded + * list of change stream events. + * + * This option is not supported for server versions < 6.0. + * * * startAfter (document): Specifies the logical starting point for the * new change stream. Unlike "resumeAfter", this option can be used with * a resume token from an "invalidate" event. @@ -229,6 +235,10 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar throw InvalidArgumentException::invalidType('"startAtOperationTime" option', $options['startAtOperationTime'], TimestampInterface::class); } + if (isset($options['showExpandedEvents']) && ! is_bool($options['showExpandedEvents'])) { + throw InvalidArgumentException::invalidType('"showExpandedEvents" option', $options['showExpandedEvents'], 'bool'); + } + /* In the absence of an explicit session, create one to ensure that the * initial aggregation and any resume attempts can use the same session * ("implicit from the user's perspective" per PHPLIB-342). Since this @@ -244,7 +254,7 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } $this->aggregateOptions = array_intersect_key($options, ['batchSize' => 1, 'collation' => 1, 'comment' => 1, 'maxAwaitTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1, 'typeMap' => 1]); - $this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'fullDocumentBeforeChange' => 1, 'resumeAfter' => 1, 'startAfter' => 1, 'startAtOperationTime' => 1]); + $this->changeStreamOptions = array_intersect_key($options, ['fullDocument' => 1, 'fullDocumentBeforeChange' => 1, 'resumeAfter' => 1, 'showExpandedEvents' => 1, 'startAfter' => 1, 'startAtOperationTime' => 1]); // Null database name implies a cluster-wide change stream if ($databaseName === null) { diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 40f746083..11dbddf16 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -491,7 +491,11 @@ function (IndexInfo $info) { assertArrayHasKey('to', $args); assertIsString($args['to']); - return $collection->rename($args['to']); + return $collection->rename( + $args['to'], + null, /* $toDatabaseName */ + array_diff_key($args, ['to' => 1]) + ); default: Assert::fail('Unsupported collection operation: ' . $this->name); diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 0e43addf4..d9a2c347f 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -55,13 +55,13 @@ final class Util 'loop' => ['operations', 'storeErrorsAsEntity', 'storeFailuresAsEntity', 'storeSuccessesAsEntity', 'storeIterationsAsEntity'], ], Client::class => [ - 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'showExpandedEvents'], 'listDatabaseNames' => ['authorizedDatabases', 'filter', 'maxTimeMS', 'session'], 'listDatabases' => ['authorizedDatabases', 'filter', 'maxTimeMS', 'session'], ], Database::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], - 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'showExpandedEvents'], 'createCollection' => ['collection', 'session', 'autoIndexId', 'capped', 'changeStreamPreAndPostImages', 'clusteredIndex', 'collation', 'expireAfterSeconds', 'flags', 'indexOptionDefaults', 'max', 'maxTimeMS', 'pipeline', 'size', 'storageEngine', 'timeseries', 'validationAction', 'validationLevel', 'validator', 'viewOn'], 'dropCollection' => ['collection', 'session'], 'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], @@ -73,7 +73,7 @@ final class Util Collection::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], - 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'comment'], + 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'comment', 'showExpandedEvents'], 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session', 'comment'], 'dropIndex' => ['name', 'session', 'maxTimeMS', 'comment'], @@ -88,7 +88,7 @@ final class Util 'find' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'findOne' => ['let', 'filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], 'findOneAndReplace' => ['let', 'returnDocument', 'filter', 'replacement', 'session', 'projection', 'returnDocument', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'new', 'remove', 'sort', 'comment'], - 'rename' => ['to', 'comment'], + 'rename' => ['to', 'comment', 'dropTarget'], 'replaceOne' => ['let', 'filter', 'replacement', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], 'findOneAndUpdate' => ['let', 'returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort', 'comment'], 'updateMany' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json new file mode 100644 index 000000000..fe852b544 --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json @@ -0,0 +1,509 @@ +{ + "description": "change-streams-showExpandedEvents", + "schemaVersion": "1.7", + "runOnRequirements": [ + { + "minServerVersion": "6.0.0", + "topologies": [ + "replicaset", + "sharded-replicaset", + "sharded" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ], + "ignoreCommandMonitoringEvents": [ + "killCursors" + ], + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + }, + { + "database": { + "id": "database1", + "client": "client0", + "databaseName": "database1" + } + }, + { + "collection": { + "id": "collection1", + "database": "database1", + "collectionName": "collection1" + } + }, + { + "database": { + "id": "shardedDb", + "client": "client0", + "databaseName": "shardedDb" + } + }, + { + "database": { + "id": "adminDb", + "client": "client0", + "databaseName": "admin" + } + }, + { + "collection": { + "id": "shardedCollection", + "database": "shardedDb", + "collectionName": "shardedCollection" + } + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [] + } + ], + "tests": [ + { + "description": "when provided, showExpandedEvents is sent as a part of the aggregate command", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "showExpandedEvents": true + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "when omitted, showExpandedEvents is not sent as a part of the aggregate command", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + } + ], + "expectEvents": [ + { + "client": "client0", + "ignoreExtraEvents": true, + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "collection0", + "cursor": {}, + "pipeline": [ + { + "$changeStream": { + "showExpandedEvents": { + "$$exists": false + } + } + } + ] + }, + "commandName": "aggregate", + "databaseName": "database0" + } + } + ] + } + ] + }, + { + "description": "when showExpandedEvents is true, new fields on change stream events are handled appropriately", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "foo" + } + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "foo" + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "a": 1 + } + } + }, + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + }, + "name": "x_1" + } + }, + { + "name": "rename", + "object": "collection0", + "arguments": { + "to": "foo", + "dropTarget": true + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "insert", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "collectionUUID": { + "$$exists": true + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "createIndexes", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "operationDescription": { + "$$exists": true + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "rename", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "to": { + "db": "database0", + "coll": "foo" + }, + "operationDescription": { + "dropTarget": { + "$$exists": true + }, + "to": { + "db": "database0", + "coll": "foo" + } + } + } + } + ] + }, + { + "description": "when showExpandedEvents is true, createIndex events are reported", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + }, + "name": "x_1" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "createIndexes" + } + } + ] + }, + { + "description": "when showExpandedEvents is true, dropIndexes events are reported", + "operations": [ + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + }, + "name": "x_1" + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "dropIndex", + "object": "collection0", + "arguments": { + "name": "x_1" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "dropIndexes" + } + } + ] + }, + { + "description": "when showExpandedEvents is true, create events are reported", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "foo" + } + }, + { + "name": "createChangeStream", + "object": "database0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "foo" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "create" + } + } + ] + }, + { + "description": "when showExpandedEvents is true, create events on views are reported", + "operations": [ + { + "name": "dropCollection", + "object": "database0", + "arguments": { + "collection": "foo" + } + }, + { + "name": "createChangeStream", + "object": "database0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "createCollection", + "object": "database0", + "arguments": { + "collection": "foo", + "viewOn": "testName" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "create" + } + } + ] + }, + { + "description": "when showExpandedEvents is true, modify events are reported", + "operations": [ + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + }, + "name": "x_2" + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "runCommand", + "object": "database0", + "arguments": { + "command": { + "collMod": "collection0" + }, + "commandName": "collMod" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "modify" + } + } + ] + }, + { + "description": "when showExpandedEvents is true, shardCollection events are reported", + "runOnRequirements": [ + { + "topologies": [ + "sharded-replicaset", + "sharded" + ] + } + ], + "operations": [ + { + "name": "dropCollection", + "object": "shardedDb", + "arguments": { + "collection": "shardedCollection" + } + }, + { + "name": "createCollection", + "object": "shardedDb", + "arguments": { + "collection": "shardedCollection" + } + }, + { + "name": "createChangeStream", + "object": "shardedCollection", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "runCommand", + "object": "adminDb", + "arguments": { + "command": { + "shardCollection": "shardedDb.shardedCollection", + "key": { + "_id": 1 + } + }, + "commandName": "shardCollection" + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "shardCollection" + } + } + ] + } + ] +} From 8dfb85fcf64eee1a1a5949e5bf24cc7697c4a20d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 14 Jul 2022 00:59:35 -0400 Subject: [PATCH 176/321] PHPLIB-882, PHPLIB-905: Update CSFLE tests for libmongocrypt 1.5.0 (#951) * PHPLIB-882: Update find payloads in CSFLE spec tests Synced with mongodb/specifications@cf7d5dd040d8a8c3714c7cad230ac204b69eeea1 * PHPLIB-905: Specify contentionFactor for explicit encryption prose tests --- tests/SpecTests/ClientSideEncryptionSpecTest.php | 4 ++++ tests/SpecTests/client-side-encryption/tests/fle2-Delete.json | 2 +- .../tests/fle2-EncryptedFields-vs-jsonSchema.json | 2 +- .../client-side-encryption/tests/fle2-FindOneAndUpdate.json | 4 ++-- .../client-side-encryption/tests/fle2-InsertFind-Indexed.json | 2 +- tests/SpecTests/client-side-encryption/tests/fle2-Update.json | 4 ++-- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 5d028d942..0474644e0 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -1284,6 +1284,7 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt $insertPayload = $clientEncryption->encrypt($value, [ 'keyId' => $key1Id, 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + 'contentionFactor' => 0, ]); $collection = $encryptedClient->selectCollection('db', 'explicit_encryption'); @@ -1293,6 +1294,7 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt 'keyId' => $key1Id, 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, 'queryType' => ClientEncryption::QUERY_TYPE_EQUALITY, + 'contentionFactor' => 0, ]); $results = $collection->find(['encryptedIndexed' => $findPayload])->toArray(); @@ -1323,6 +1325,7 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt 'keyId' => $key1Id, 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, 'queryType' => ClientEncryption::QUERY_TYPE_EQUALITY, + 'contentionFactor' => 0, ]); $results = $collection->find(['encryptedIndexed' => $findPayload])->toArray(); @@ -1378,6 +1381,7 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt $payload = $clientEncryption->encrypt($value, [ 'keyId' => $key1Id, 'algorithm' => ClientEncryption::ALGORITHM_INDEXED, + 'contentionFactor' => 0, ]); $test->assertSame($value, $clientEncryption->decrypt($payload)); diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json index 790e81829..0e3e06396 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json @@ -225,7 +225,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json index 69abfa7cf..1d3227ee7 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json @@ -230,7 +230,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json index b8088515c..b31438876 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json @@ -230,7 +230,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } @@ -490,7 +490,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json index 142cacf2f..81a549590 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json @@ -226,7 +226,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json index 66a291902..87830af32 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json @@ -232,7 +232,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } @@ -496,7 +496,7 @@ "encryptedIndexed": { "$eq": { "$binary": { - "base64": "BYkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcSY20AAAAAAAAAAAAA", + "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==", "subType": "06" } } From a9d82890fe0c104cf795e6c759c92484d12c027a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 14 Jul 2022 01:07:37 -0400 Subject: [PATCH 177/321] PHPLIB-893: Automatic queryable encryption in CSFLE tutorial (#952) --- docs/tutorial/client-side-encryption.txt | 98 +++++++++++++++++++++++- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/docs/tutorial/client-side-encryption.txt b/docs/tutorial/client-side-encryption.txt index 184bcc07c..6ed2e00d4 100644 --- a/docs/tutorial/client-side-encryption.txt +++ b/docs/tutorial/client-side-encryption.txt @@ -21,8 +21,8 @@ Automatic Encryption and Decryption Auto encryption is an enterprise only feature. -The following example uses a local key, however using AWS Key Management Service -is also an option. The data in the ``encryptedField`` field is automatically +The following example uses a local key; however, other key providers such as AWS +are also an option. The data in the ``encryptedField`` field is automatically encrypted on insertion and decrypted when querying on the client side. .. code-block:: php @@ -31,6 +31,7 @@ encrypted on insertion and decrypted when querying on the client side. use MongoDB\BSON\Binary; use MongoDB\Client; + use MongoDB\Driver\ClientEncryption; $localKey = new Binary('', Binary::TYPE_GENERIC); @@ -41,7 +42,7 @@ encrypted on insertion and decrypted when querying on the client side. ], ]; - $client = new Client('mongodb://127.0.0.1'); + $client = new Client(); $clientEncryption = $client->createClientEncryption($encryptionOpts); $database = $client->selectDatabase('test'); @@ -134,7 +135,7 @@ encryption using the newly created key. ], ]; - $encryptedClient = new Client('mongodb://127.0.0.1', [], ['autoEncryption' => $autoEncryptionOpts]); + $encryptedClient = new Client(null, [], ['autoEncryption' => $autoEncryptionOpts]); $collection = $encryptedClient->selectCollection('test', 'coll'); $collection->drop(); // clear old data @@ -239,3 +240,92 @@ The software then encrypts data by referencing the key by its alternative name. $document = $collection->findOne(); var_dump($clientEncryption->decrypt($document->encryptedField)); + + +Automatic Queryable Encryption +------------------------------ + +.. note:: + + Automatic queryable encryption is an enterprise only feature and requires + MongoDB 6.0+. + +The following example uses a local key; however, other key providers such as AWS +are also an option. The data in the ``encryptedIndexed`` and +``encryptedUnindexed`` fields will be automatically encrypted on insertion and +decrypted when querying on the client side. Additionally, it is possible to +query on the ``encryptedIndexed`` field. + +.. code-block:: php + + ', Binary::TYPE_GENERIC); + + $encryptionOpts = [ + 'keyVaultNamespace' => 'encryption.__keyVault', + 'kmsProviders' => ['local' => ['key' => $localKey]], + ]; + + $client = new Client(); + $clientEncryption = $client->createClientEncryption($encryptionOpts); + + // Create two data keys, one for each encrypted field + $dataKeyId1 = $clientEncryption->createDataKey('local'); + $dataKeyId2 = $clientEncryption->createDataKey('local'); + + $autoEncryptionOpts = [ + 'keyVaultNamespace' => 'encryption.__keyVault', + 'kmsProviders' => ['local' => ['key' => $localKey]], + 'encryptedFieldsMap' => [ + 'test.coll' => [ + 'fields' => [ + [ + 'path' => 'encryptedIndexed', + 'bsonType' => 'string', + 'keyId' => $dataKeyId1, + 'queries' => ['queryType' => 'equality'], + ], + [ + 'path' => 'encryptedUnindexed', + 'bsonType' => 'string', + 'keyId' => $dataKeyId2, + ], + ], + ], + ], + ]; + + $encryptedClient = new Client(null, [], ['autoEncryption' => $autoEncryptionOpts]); + + /* Drop and create the collection under test. The createCollection() helper + * will reference the client's encryptedFieldsMap and create additional, + * internal collections automatically. */ + $encryptedClient->selectDatabase('test')->dropCollection('coll'); + $encryptedClient->selectDatabase('test')->createCollection('coll'); + $encryptedCollection = $encryptedClient->selectCollection('test', 'coll'); + + /* Using a client with auto encryption, insert a document with encrypted + * fields and assert that those fields are automatically decrypted when + * querying. The encryptedIndexed and encryptedUnindexed fields should both + * be strings. */ + $indexedValue = 'indexedValue'; + $unindexedValue = 'unindexedValue'; + + $encryptedCollection->insertOne([ + '_id' => 1, + 'encryptedIndexed' => $indexedValue, + 'encryptedUnindexed' => $unindexedValue, + ]); + + var_dump($encryptedCollection->findOne(['encryptedIndexed' => $indexedValue])); + + /* Using a client without auto encryption, query for the same document and + * assert that encrypted data is returned. The encryptedIndexed and + * encryptedUnindexed fields should both be Binary objects. */ + $unencryptedCollection = $client->selectCollection('test', 'coll'); + + var_dump($unencryptedCollection->findOne(['_id' => 1])); From 3ddb447da95fa9696efd1ccabe23b56738d95fb6 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 26 Jul 2022 09:50:32 -0400 Subject: [PATCH 178/321] Master is now 1.14-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index deab69b72..2117537b2 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.13.x-dev" + "dev-master": "1.14.x-dev" } }, "config": { From cb9331fd042d53624e3036a04879e39430e61497 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 5 Aug 2022 15:59:53 +0200 Subject: [PATCH 179/321] PHPLIB-933: Test on PHP 8.2 (#953) * Add testing for feature branches to GitHub Actions * Test on PHP 8.2 * Handle upcoming return type changes * Handle missing class properties * No longer use self in callable --- .github/workflows/tests.yml | 3 +++ src/Model/BSONArray.php | 2 ++ src/Model/BSONDocument.php | 2 ++ src/Model/ChangeStreamIterator.php | 6 +++--- src/Model/IndexInput.php | 2 ++ src/Operation/Watch.php | 6 +++--- tests/GridFS/UnusableStream.php | 2 ++ tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php | 4 ++-- tests/UnifiedSpecTests/Constraint/Matches.php | 3 +++ tests/UnifiedSpecTests/Operation.php | 11 ++++++++--- 10 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 293862ccd..e3372df4c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -5,10 +5,12 @@ on: branches: - "v*.*" - "master" + - "feature/*" push: branches: - "v*.*" - "master" + - "feature/*" jobs: phpunit: @@ -24,6 +26,7 @@ jobs: - "7.4" - "8.0" - "8.1" + - "8.2" mongodb-version: - "4.4" driver-version: diff --git a/src/Model/BSONArray.php b/src/Model/BSONArray.php index 0b49fd98f..74d0caf40 100644 --- a/src/Model/BSONArray.php +++ b/src/Model/BSONArray.php @@ -71,6 +71,7 @@ public static function __set_state(array $properties) * @see https://php.net/mongodb-bson-serializable.bsonserialize * @return array */ + #[ReturnTypeWillChange] public function bsonSerialize() { return array_values($this->getArrayCopy()); @@ -82,6 +83,7 @@ public function bsonSerialize() * @see https://php.net/mongodb-bson-unserializable.bsonunserialize * @param array $data Array data */ + #[ReturnTypeWillChange] public function bsonUnserialize(array $data) { self::__construct($data); diff --git a/src/Model/BSONDocument.php b/src/Model/BSONDocument.php index ab8cb5375..af439f8ad 100644 --- a/src/Model/BSONDocument.php +++ b/src/Model/BSONDocument.php @@ -81,6 +81,7 @@ public static function __set_state(array $properties) * @see https://php.net/mongodb-bson-serializable.bsonserialize * @return object */ + #[ReturnTypeWillChange] public function bsonSerialize() { return (object) $this->getArrayCopy(); @@ -92,6 +93,7 @@ public function bsonSerialize() * @see https://php.net/mongodb-bson-unserializable.bsonunserialize * @param array $data Array data */ + #[ReturnTypeWillChange] public function bsonUnserialize(array $data) { parent::__construct($data, ArrayObject::ARRAY_AS_PROPS); diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index f8c40c1b5..307a68edc 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -100,12 +100,12 @@ public function __construct(Cursor $cursor, $firstBatchSize, $initialResumeToken } /** @internal */ - final public function commandFailed(CommandFailedEvent $event) + final public function commandFailed(CommandFailedEvent $event): void { } /** @internal */ - final public function commandStarted(CommandStartedEvent $event) + final public function commandStarted(CommandStartedEvent $event): void { if ($event->getCommandName() !== 'getMore') { return; @@ -117,7 +117,7 @@ final public function commandStarted(CommandStartedEvent $event) } /** @internal */ - final public function commandSucceeded(CommandSucceededEvent $event) + final public function commandSucceeded(CommandSucceededEvent $event): void { if ($event->getCommandName() !== 'getMore') { return; diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php index 584d8f912..5c6342b4c 100644 --- a/src/Model/IndexInput.php +++ b/src/Model/IndexInput.php @@ -19,6 +19,7 @@ use MongoDB\BSON\Serializable; use MongoDB\Exception\InvalidArgumentException; +use ReturnTypeWillChange; use function is_array; use function is_float; @@ -91,6 +92,7 @@ public function __toString() * @see https://php.net/mongodb-bson-serializable.bsonserialize * @return array */ + #[ReturnTypeWillChange] public function bsonSerialize() { return $this->index; diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 7c0ebea04..3daf2d26a 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -271,12 +271,12 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } /** @internal */ - final public function commandFailed(CommandFailedEvent $event) + final public function commandFailed(CommandFailedEvent $event): void { } /** @internal */ - final public function commandStarted(CommandStartedEvent $event) + final public function commandStarted(CommandStartedEvent $event): void { if ($event->getCommandName() !== 'aggregate') { return; @@ -287,7 +287,7 @@ final public function commandStarted(CommandStartedEvent $event) } /** @internal */ - final public function commandSucceeded(CommandSucceededEvent $event) + final public function commandSucceeded(CommandSucceededEvent $event): void { if ($event->getCommandName() !== 'aggregate') { return; diff --git a/tests/GridFS/UnusableStream.php b/tests/GridFS/UnusableStream.php index 328d7b3af..c7686638b 100644 --- a/tests/GridFS/UnusableStream.php +++ b/tests/GridFS/UnusableStream.php @@ -12,6 +12,8 @@ final class UnusableStream { + public $context; + public static function register($protocol = 'unusable'): void { if (in_array($protocol, stream_get_wrappers())) { diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php index 69564af87..730dc7935 100644 --- a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php +++ b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php @@ -163,7 +163,7 @@ private function assertResult($expected, Constraint $constraint, $value, string // phpcs:disable Squiz.Classes.ClassFileName.NoMatch class SerializableArray implements Serializable { - public function bsonSerialize() + public function bsonSerialize(): array { return ['foo']; } @@ -171,7 +171,7 @@ public function bsonSerialize() class SerializableObject implements Serializable { - public function bsonSerialize() + public function bsonSerialize(): array { return ['x' => 1]; } diff --git a/tests/UnifiedSpecTests/Constraint/Matches.php b/tests/UnifiedSpecTests/Constraint/Matches.php index aebd72510..eea67a153 100644 --- a/tests/UnifiedSpecTests/Constraint/Matches.php +++ b/tests/UnifiedSpecTests/Constraint/Matches.php @@ -68,6 +68,9 @@ class Matches extends Constraint /** @var ComparisonFailure|null */ private $lastFailure; + /** @var Factory */ + private $comparatorFactory; + public function __construct($value, ?EntityMap $entityMap = null, $allowExtraRootKeys = true, $allowOperators = true) { $this->value = self::prepare($value); diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index 11dbddf16..d7b377a4e 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -85,10 +85,10 @@ final class Operation private $entityMap; /** @var ExpectedError */ - private $expectedError; + private $expectError; /** @var ExpectedResult */ - private $expectedResult; + private $expectResult; /** @var bool */ private $ignoreResultAndError; @@ -295,7 +295,12 @@ private function executeForCollection(Collection $collection) assertIsArray($args['requests']); return $collection->bulkWrite( - array_map('self::prepareBulkWriteRequest', $args['requests']), + array_map( + static function ($request) { + return self::prepareBulkWriteRequest($request); + }, + $args['requests'] + ), array_diff_key($args, ['requests' => 1]) ); From 0c3bc18201e53fddb245d0e3c8fb7804742f7493 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 9 Aug 2022 09:33:28 -0400 Subject: [PATCH 180/321] PHPLIB-936: Update schemaVersion in load balancer spec tests (#956) Synced with mongodb/specifications@008d2f5aab41dabced03e0860bab614c0f15ded5 --- tests/UnifiedSpecTests/load-balancers/cursors.json | 2 +- tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json | 2 +- tests/UnifiedSpecTests/load-balancers/transactions.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/UnifiedSpecTests/load-balancers/cursors.json b/tests/UnifiedSpecTests/load-balancers/cursors.json index 6eddc0ebc..8454f130d 100644 --- a/tests/UnifiedSpecTests/load-balancers/cursors.json +++ b/tests/UnifiedSpecTests/load-balancers/cursors.json @@ -1,6 +1,6 @@ { "description": "cursors are correctly pinned to connections for load-balanced clusters", - "schemaVersion": "1.3", + "schemaVersion": "1.4", "runOnRequirements": [ { "topologies": [ diff --git a/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json b/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json index 4ab34b1fe..083c98e94 100644 --- a/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json +++ b/tests/UnifiedSpecTests/load-balancers/sdam-error-handling.json @@ -1,6 +1,6 @@ { "description": "state change errors are correctly handled", - "schemaVersion": "1.3", + "schemaVersion": "1.4", "runOnRequirements": [ { "topologies": [ diff --git a/tests/UnifiedSpecTests/load-balancers/transactions.json b/tests/UnifiedSpecTests/load-balancers/transactions.json index 8cf24f4ca..0dd04ee85 100644 --- a/tests/UnifiedSpecTests/load-balancers/transactions.json +++ b/tests/UnifiedSpecTests/load-balancers/transactions.json @@ -1,6 +1,6 @@ { "description": "transactions are correctly pinned to connections for load-balanced clusters", - "schemaVersion": "1.3", + "schemaVersion": "1.4", "runOnRequirements": [ { "topologies": [ From ece69fb12feb573a52b0a0fca84e18f4fe5d869d Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 23 Aug 2022 08:42:15 +0200 Subject: [PATCH 181/321] PHPLIB-715: Use flexible numeric comparisons in DocumentMatchConstraint (#958) * PHPLIB-715: Use flexible numeric comparisons in DocumentMatchConstraint * Fix phpcs --- tests/SpecTests/DocumentsMatchConstraint.php | 41 ++++++------------- .../DocumentsMatchConstraintTest.php | 23 +++++------ tests/SpecTests/Operation.php | 7 +++- tests/SpecTests/RetryableReadsSpecTest.php | 2 +- .../Constraint/MatchesTest.php | 8 ++++ 5 files changed, 38 insertions(+), 43 deletions(-) diff --git a/tests/SpecTests/DocumentsMatchConstraint.php b/tests/SpecTests/DocumentsMatchConstraint.php index 786350433..b512cfd28 100644 --- a/tests/SpecTests/DocumentsMatchConstraint.php +++ b/tests/SpecTests/DocumentsMatchConstraint.php @@ -35,10 +35,10 @@ use function array_values; use function get_class; use function get_debug_type; -use function in_array; use function is_array; +use function is_float; +use function is_int; use function is_object; -use function is_scalar; use function method_exists; use function sprintf; @@ -59,9 +59,6 @@ class DocumentsMatchConstraint extends Constraint /** @var boolean */ private $ignoreExtraKeysInEmbedded = false; - /** @var array */ - private $placeholders = []; - /** * TODO: This is not currently used, but was preserved from the design of * TestCase::assertMatchesDocument(), which would sort keys and then compare @@ -88,14 +85,12 @@ class DocumentsMatchConstraint extends Constraint * @param array|object $value * @param boolean $ignoreExtraKeysInRoot If true, ignore extra keys within the root document * @param boolean $ignoreExtraKeysInEmbedded If true, ignore extra keys within embedded documents - * @param array $placeholders Placeholders for any value */ - public function __construct($value, bool $ignoreExtraKeysInRoot = false, bool $ignoreExtraKeysInEmbedded = false, array $placeholders = []) + public function __construct($value, bool $ignoreExtraKeysInRoot = false, bool $ignoreExtraKeysInEmbedded = false) { $this->value = $this->prepareBSON($value, true, $this->sortKeys); $this->ignoreExtraKeysInRoot = $ignoreExtraKeysInRoot; $this->ignoreExtraKeysInEmbedded = $ignoreExtraKeysInEmbedded; - $this->placeholders = $placeholders; $this->comparatorFactory = Factory::getInstance(); } @@ -303,10 +298,6 @@ private function assertEquals(ArrayObject $expected, ArrayObject $actual, bool $ throw new RuntimeException(sprintf('$actual is missing key: "%s"', $keyPrefix . $key)); } - if (in_array($expectedValue, $this->placeholders, true)) { - continue; - } - $actualValue = $actual[$key]; if ($expectedValue instanceof BSONDocument && isset($expectedValue['$$type'])) { @@ -322,26 +313,13 @@ private function assertEquals(ArrayObject $expected, ArrayObject $actual, bool $ continue; } - if (is_scalar($expectedValue) && is_scalar($actualValue)) { - if ($expectedValue !== $actualValue) { - throw new ComparisonFailure( - $expectedValue, - $actualValue, - '', - '', - false, - sprintf('Field path "%s": %s', $keyPrefix . $key, 'Failed asserting that two values are equal.') - ); - } - - continue; - } - $expectedType = get_debug_type($expectedValue); $actualType = get_debug_type($actualValue); - // Workaround for ObjectComparator printing the whole actual object - if ($expectedType !== $actualType) { + /* Early check to work around ObjectComparator printing the entire value + * for a failed type comparison. Avoid doing this if either value is + * numeric to allow for flexible numeric comparisons (e.g. 1 == 1.0). */ + if ($expectedType !== $actualType && ! (self::isNumeric($expectedValue) || self::isNumeric($actualValue))) { throw new ComparisonFailure( $expectedValue, $actualValue, @@ -421,6 +399,11 @@ private function doToString() return 'matches ' . $this->exporter()->export($this->value); } + private static function isNumeric($value): bool + { + return is_int($value) || is_float($value) || $value instanceof Int64; + } + /** * Prepare a BSON document or array for comparison. * diff --git a/tests/SpecTests/DocumentsMatchConstraintTest.php b/tests/SpecTests/DocumentsMatchConstraintTest.php index eca64d344..1917d4c69 100644 --- a/tests/SpecTests/DocumentsMatchConstraintTest.php +++ b/tests/SpecTests/DocumentsMatchConstraintTest.php @@ -43,6 +43,14 @@ public function testIgnoreExtraKeysInRoot(): void $this->assertResult(false, $c, [1, ['a' => 1, 'b' => 2]], 'Extra keys in embedded are not permitted'); } + public function testFlexibleNumericComparison(): void + { + $c = new DocumentsMatchConstraint(['x' => 1, 'y' => 1.0]); + $this->assertResult(true, $c, ['x' => 1.0, 'y' => 1.0], 'Float instead of expected int matches'); + $this->assertResult(true, $c, ['x' => 1, 'y' => 1], 'Int instead of expected float matches'); + $this->assertResult(false, $c, ['x' => 'foo', 'y' => 1.0], 'Different type does not match'); + } + public function testIgnoreExtraKeysInEmbedded(): void { $c = new DocumentsMatchConstraint(['x' => 1, 'y' => ['a' => 1, 'b' => 2]], false, true); @@ -64,15 +72,6 @@ public function testIgnoreExtraKeysInEmbedded(): void $this->assertResult(false, $c, [1, ['a' => 2]], 'Keys must have the correct value'); } - public function testPlaceholders(): void - { - $c = new DocumentsMatchConstraint(['x' => '42', 'y' => 42, 'z' => ['a' => 24]], false, false, [24, 42]); - - $this->assertResult(true, $c, ['x' => '42', 'y' => 'foo', 'z' => ['a' => 1]], 'Placeholders accept any value'); - $this->assertResult(false, $c, ['x' => 42, 'y' => 'foo', 'z' => ['a' => 1]], 'Placeholder type must match'); - $this->assertResult(true, $c, ['x' => '42', 'y' => 42, 'z' => ['a' => 24]], 'Exact match'); - } - /** * @dataProvider provideBSONTypes */ @@ -146,13 +145,13 @@ public function errorMessageProvider() ['foo' => ['foo' => 'bar', 'bar' => 'baz']], ], 'Scalar value not equal' => [ - 'Field path "foo": Failed asserting that two values are equal.', + 'Field path "foo": Failed asserting that two strings are equal.', new DocumentsMatchConstraint(['foo' => 'bar']), ['foo' => 'baz'], ], 'Scalar type mismatch' => [ - 'Field path "foo": Failed asserting that two values are equal.', - new DocumentsMatchConstraint(['foo' => 42]), + 'Field path "foo": \'42\' is not instance of expected type "bool".', + new DocumentsMatchConstraint(['foo' => true]), ['foo' => '42'], ], 'Type mismatch' => [ diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index dc5cd2b37..25f1c07d4 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -12,6 +12,7 @@ use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\GridFS\Bucket; +use MongoDB\MapReduceResult; use MongoDB\Model\IndexInfo; use MongoDB\Operation\FindOneAndReplace; use MongoDB\Operation\FindOneAndUpdate; @@ -206,6 +207,10 @@ public function assert(FunctionalTestCase $test, Context $context, bool $bubbleE * is not used (e.g. Command Monitoring spec). */ if ($result instanceof Cursor) { $result = $result->toArray(); + } elseif ($result instanceof MapReduceResult) { + /* For mapReduce operations, we ignore the mapReduce metadata + * and only return the result iterator for evaluation. */ + $result = iterator_to_array($result->getIterator()); } } catch (Exception $e) { $exception = $e; @@ -789,7 +794,7 @@ private function getResultAssertionTypeForCollection() return ResultExpectation::ASSERT_SAME_DOCUMENTS; case 'mapReduce': - return ResultExpectation::ASSERT_SAME_DOCUMENTS; + return ResultExpectation::ASSERT_DOCUMENTS_MATCH; case 'replaceOne': case 'updateMany': diff --git a/tests/SpecTests/RetryableReadsSpecTest.php b/tests/SpecTests/RetryableReadsSpecTest.php index e747124ee..37465aff9 100644 --- a/tests/SpecTests/RetryableReadsSpecTest.php +++ b/tests/SpecTests/RetryableReadsSpecTest.php @@ -26,7 +26,7 @@ class RetryableReadsSpecTest extends FunctionalTestCase ]; /** @var array */ - private static $incompleteTests = ['mapReduce: MapReduce succeeds with retry on' => 'PHPLIB-715']; + private static $incompleteTests = []; /** * Assert that the expected and actual command documents match. diff --git a/tests/UnifiedSpecTests/Constraint/MatchesTest.php b/tests/UnifiedSpecTests/Constraint/MatchesTest.php index 50b13a4de..72433b3e0 100644 --- a/tests/UnifiedSpecTests/Constraint/MatchesTest.php +++ b/tests/UnifiedSpecTests/Constraint/MatchesTest.php @@ -23,6 +23,14 @@ public function testMatchesDocument(): void $this->assertResult(true, $c, ['y' => ['b' => 2, 'a' => 1], 'x' => 1], 'Root and embedded key order is not significant'); } + public function testFlexibleNumericComparison(): void + { + $c = new Matches(['x' => 1, 'y' => 1.0]); + $this->assertResult(true, $c, ['x' => 1.0, 'y' => 1.0], 'Float instead of expected int matches'); + $this->assertResult(true, $c, ['x' => 1, 'y' => 1], 'Int instead of expected float matches'); + $this->assertResult(false, $c, ['x' => 'foo', 'y' => 1.0], 'Different type does not match'); + } + public function testDoNotAllowExtraRootKeys(): void { $c = new Matches(['x' => 1], null, false); From 5d48a1ed3e3700fb4b53d623977244c461ad699c Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 23 Aug 2022 16:45:27 -0400 Subject: [PATCH 182/321] PHPLIB-820: Key Management API spec tests (#957) * Unified spec and prose tests for CSFLE key management API Support runOnRequirement.csfle, clientEncryption entity/operations, and $$placeholder syntax Synced with mongodb/specifications@10b4a41f8d282cebc5d3681adba27de18539d9f4 * Note ClientEncryption's parent client to ensure events are observed * Set ClientEncryption tlsOptions when KMIP endpoint is used * PHPLIB-929: Prose test for rewrapManyDataKey * Do not consider SkippedTest exceptions as errors for valid-fail tests This is particularly relevant for kmsProviders tests, which may need to be skipped according to runOnRequirements.csfle --- .evergreen/config.yml | 16 +- tests/FunctionalTestCase.php | 32 +- .../ClientSideEncryptionSpecTest.php | 166 ++ tests/UnifiedSpecTests/Context.php | 93 ++ tests/UnifiedSpecTests/EntityMap.php | 2 + tests/UnifiedSpecTests/Operation.php | 84 + tests/UnifiedSpecTests/RunOnRequirement.php | 16 +- tests/UnifiedSpecTests/UnifiedSpecTest.php | 25 +- tests/UnifiedSpecTests/UnifiedTestRunner.php | 49 +- tests/UnifiedSpecTests/Util.php | 11 + .../client-side-encryption/addKeyAltName.json | 609 +++++++ .../createDataKey-kms_providers-invalid.json | 119 ++ .../client-side-encryption/createDataKey.json | 711 ++++++++ .../client-side-encryption/deleteKey.json | 557 +++++++ .../client-side-encryption/getKey.json | 319 ++++ .../getKeyByAltName.json | 289 ++++ .../client-side-encryption/getKeys.json | 260 +++ .../removeKeyAltName.json | 672 ++++++++ .../rewrapManyDataKey-decrypt_failure.json | 162 ++ .../rewrapManyDataKey-encrypt_failure.json | 250 +++ .../rewrapManyDataKey.json | 1475 +++++++++++++++++ ...Providers-missing_aws_kms_credentials.json | 36 + ...oviders-missing_azure_kms_credentials.json | 36 + ...Providers-missing_gcp_kms_credentials.json | 36 + .../valid-fail/kmsProviders-no_kms.json | 32 + .../collectionData-createOptions.json | 69 + .../valid-pass/createEntities-operation.json | 74 + .../valid-pass/entity-cursor-iterateOnce.json | 108 ++ ...kmsProviders-explicit_kms_credentials.json | 52 + ...Providers-mixed_kms_credential_fields.json | 54 + ...Providers-placeholder_kms_credentials.json | 70 + .../kmsProviders-unconfigured_kms.json | 39 + .../valid-pass/matches-lte-operator.json | 78 + .../valid-pass/poc-change-streams.json | 36 + 34 files changed, 6609 insertions(+), 28 deletions(-) create mode 100644 tests/UnifiedSpecTests/client-side-encryption/addKeyAltName.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/createDataKey-kms_providers-invalid.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/createDataKey.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/deleteKey.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/getKey.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/getKeyByAltName.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/getKeys.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/removeKeyAltName.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-decrypt_failure.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-encrypt_failure.json create mode 100644 tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json create mode 100644 tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_aws_kms_credentials.json create mode 100644 tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_azure_kms_credentials.json create mode 100644 tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_gcp_kms_credentials.json create mode 100644 tests/UnifiedSpecTests/valid-fail/kmsProviders-no_kms.json create mode 100644 tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json create mode 100644 tests/UnifiedSpecTests/valid-pass/createEntities-operation.json create mode 100644 tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json create mode 100644 tests/UnifiedSpecTests/valid-pass/kmsProviders-explicit_kms_credentials.json create mode 100644 tests/UnifiedSpecTests/valid-pass/kmsProviders-mixed_kms_credential_fields.json create mode 100644 tests/UnifiedSpecTests/valid-pass/kmsProviders-placeholder_kms_credentials.json create mode 100644 tests/UnifiedSpecTests/valid-pass/kmsProviders-unconfigured_kms.json create mode 100644 tests/UnifiedSpecTests/valid-pass/matches-lte-operator.json diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 69333d384..044b84c4e 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -621,22 +621,22 @@ axes: - id: driver-versions display_name: Driver Version values: - # TODO: Update to "1.14.0" once PHPC 1.14.0 is released + # TODO: Update to "1.15.0" once PHPC 1.15.0 is released - id: "oldest-supported" - # display_name: "1.14.0" - display_name: "PHPC 1.14-dev (master)" + # display_name: "1.15.0" + display_name: "PHPC 1.15-dev (master)" variables: - # EXTENSION_VERSION: "1.14.0" + # EXTENSION_VERSION: "1.15.0" EXTENSION_BRANCH: "master" - # TODO: Update to "1.14.x"/"stable" once PHPC 1.14.0 is released + # TODO: Update to "1.15.x"/"stable" once PHPC 1.15.0 is released - id: "latest-stable" - # display_name: "1.14.x" - display_name: "PHPC 1.14-dev (master)" + # display_name: "1.15.x" + display_name: "PHPC 1.15-dev (master)" variables: # EXTENSION_VERSION: "stable" EXTENSION_BRANCH: "master" - id: "latest-dev" - display_name: "PHPC 1.14-dev (master)" + display_name: "PHPC 1.15-dev (master)" variables: EXTENSION_BRANCH: "master" diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index dcab12d36..36992c965 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -284,6 +284,21 @@ public function configureFailPoint($command, ?Server $server = null): void $this->configuredFailPoints[] = [$command->configureFailPoint, $failPointServer]; } + public static function getModuleInfo(string $row): ?string + { + ob_start(); + phpinfo(INFO_MODULES); + $info = ob_get_clean(); + + $pattern = sprintf('/^%s([\w ]+)$/m', preg_quote($row . ' => ')); + + if (preg_match($pattern, $info, $matches) !== 1) { + return null; + } + + return $matches[1]; + } + /** * Creates the test collection with the specified options. * @@ -512,7 +527,7 @@ protected function skipIfClientSideEncryptionIsNotSupported(): void $this->markTestSkipped('Client Side Encryption only supported on FCV 4.2 or higher'); } - if ($this->getModuleInfo('libmongocrypt') === 'disabled') { + if (static::getModuleInfo('libmongocrypt') === 'disabled') { $this->markTestSkipped('Client Side Encryption is not enabled in the MongoDB extension'); } } @@ -598,21 +613,6 @@ private function disableFailPoints(): void } } - private function getModuleInfo(string $row): ?string - { - ob_start(); - phpinfo(INFO_MODULES); - $info = ob_get_clean(); - - $pattern = sprintf('/^%s([\w ]+)$/m', preg_quote($row . ' => ')); - - if (preg_match($pattern, $info, $matches) !== 1) { - return null; - } - - return $matches[1]; - } - /** * Checks if the failCommand command is supported on this server version * diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 0474644e0..4fb9bad70 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -15,6 +15,7 @@ use MongoDB\Driver\Exception\ConnectionTimeoutException; use MongoDB\Driver\Exception\EncryptionException; use MongoDB\Driver\Exception\RuntimeException; +use MongoDB\Driver\Exception\ServerException; use MongoDB\Driver\Monitoring\CommandFailedEvent; use MongoDB\Driver\Monitoring\CommandStartedEvent; use MongoDB\Driver\Monitoring\CommandSubscriber; @@ -1403,6 +1404,93 @@ static function (self $test, ClientEncryption $clientEncryption, Client $encrypt ]; } + /** + * Prose test 13: Unique Index on keyAltNames + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#unique-index-on-keyaltnames + * @dataProvider provideUniqueIndexOnKeyAltNamesTests + */ + public function testUniqueIndexOnKeyAltNames(Closure $test): void + { + // Test setup + $client = static::createTestClient(); + + // Ensure that the key vault is dropped with a majority write concern + self::insertKeyVaultData($client, []); + + $client->selectCollection('keyvault', 'datakeys')->createIndex( + ['keyAltNames' => 1], + [ + 'unique' => true, + 'partialFilterExpression' => ['keyAltNames' => ['$exists' => true]], + 'writeConcern' => new WriteConcern(WriteConcern::MAJORITY), + ] + ); + + $clientEncryption = new ClientEncryption([ + 'keyVaultClient' => $client->getManager(), + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]], + ]); + + $clientEncryption->createDataKey('local', ['keyAltNames' => ['def']]); + + $test($this, $client, $clientEncryption); + } + + public static function provideUniqueIndexOnKeyAltNamesTests() + { + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-1-createdatakey + yield 'Case 1: createDataKey()' => [ + static function (self $test, Client $client, ClientEncryption $clientEncryption): void { + $clientEncryption->createDataKey('local', ['keyAltNames' => ['abc']]); + + try { + $clientEncryption->createDataKey('local', ['keyAltNames' => ['abc']]); + $test->fail('Expected exception to be thrown'); + } catch (ServerException $e) { + $test->assertSame(11000 /* DuplicateKey */, $e->getCode()); + } + + try { + $clientEncryption->createDataKey('local', ['keyAltNames' => ['def']]); + $test->fail('Expected exception to be thrown'); + } catch (ServerException $e) { + $test->assertSame(11000 /* DuplicateKey */, $e->getCode()); + } + }, + ]; + + // See: https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-2-addkeyaltname + yield 'Case 2: addKeyAltName()' => [ + static function (self $test, Client $client, ClientEncryption $clientEncryption): void { + $keyId = $clientEncryption->createDataKey('local'); + + $keyBeforeUpdate = $clientEncryption->addKeyAltName($keyId, 'abc'); + $test->assertObjectNotHasAttribute('keyAltNames', $keyBeforeUpdate); + + $keyBeforeUpdate = $clientEncryption->addKeyAltName($keyId, 'abc'); + $test->assertObjectHasAttribute('keyAltNames', $keyBeforeUpdate); + $test->assertIsArray($keyBeforeUpdate->keyAltNames); + $test->assertContains('abc', $keyBeforeUpdate->keyAltNames); + + try { + $clientEncryption->addKeyAltName($keyId, 'def'); + $test->fail('Expected exception to be thrown'); + } catch (ServerException $e) { + $test->assertSame(11000 /* DuplicateKey */, $e->getCode()); + } + + $originalKeyId = $clientEncryption->getKeyByAltName('def')->_id; + + $originalKeyBeforeUpdate = $clientEncryption->addKeyAltName($originalKeyId, 'def'); + $test->assertObjectHasAttribute('keyAltNames', $originalKeyBeforeUpdate); + $test->assertIsArray($originalKeyBeforeUpdate->keyAltNames); + $test->assertContains('def', $originalKeyBeforeUpdate->keyAltNames); + }, + ]; + } + /** * Prose test 14: Decryption Events * @@ -1552,6 +1640,84 @@ static function (self $test, Client $setupClient, ClientEncryption $clientEncryp ]; } + /** + * Prose test 16: RewrapManyDataKey + * + * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#rewrap + * @dataProvider provideRewrapManyDataKeySrcAndDstProviders + */ + public function testRewrapManyDataKey(string $srcProvider, string $dstProvider): void + { + $providerMasterKeys = [ + 'aws' => ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0'], + 'azure' => ['keyVaultEndpoint' => 'key-vault-csfle.vault.azure.net', 'keyName' => 'key-name-csfle'], + 'gcp' => ['projectId' => 'devprod-drivers', 'location' => 'global', 'keyRing' => 'key-ring-csfle', 'keyName' => 'key-name-csfle'], + 'kmip' => [], + ]; + + // Test setup + $client = static::createTestClient(); + + // Ensure that the key vault is dropped with a majority write concern + self::insertKeyVaultData($client, []); + + $clientEncryptionOpts = [ + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => [ + 'aws' => Context::getAWSCredentials(), + 'azure' => Context::getAzureCredentials(), + 'gcp' => Context::getGCPCredentials(), + 'kmip' => ['endpoint' => Context::getKmipEndpoint()], + 'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)], + ], + 'tlsOptions' => [ + 'kmip' => Context::getKmsTlsOptions(), + ], + ]; + + $clientEncryption1 = $client->createClientEncryption($clientEncryptionOpts); + + $createDataKeyOpts = []; + + if (isset($providerMasterKeys[$srcProvider])) { + $createDataKeyOpts['masterKey'] = $providerMasterKeys[$srcProvider]; + } + + $keyId = $clientEncryption1->createDataKey($srcProvider, $createDataKeyOpts); + + $ciphertext = $clientEncryption1->encrypt('test', ['algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, 'keyId' => $keyId]); + + $clientEncryption2 = $client->createClientEncryption($clientEncryptionOpts); + + $rewrapManyDataKeyOpts = ['provider' => $dstProvider]; + + if (isset($providerMasterKeys[$dstProvider])) { + $rewrapManyDataKeyOpts['masterKey'] = $providerMasterKeys[$dstProvider]; + } + + $result = $clientEncryption2->rewrapManyDataKey([], $rewrapManyDataKeyOpts); + + $this->assertObjectHasAttribute('bulkWriteResult', $result); + $this->assertIsObject($result->bulkWriteResult); + // libmongoc uses different field names for its BulkWriteResult + $this->assertObjectHasAttribute('nModified', $result->bulkWriteResult); + $this->assertSame(1, $result->bulkWriteResult->nModified); + + $this->assertSame('test', $clientEncryption1->decrypt($ciphertext)); + $this->assertSame('test', $clientEncryption2->decrypt($ciphertext)); + } + + public static function provideRewrapManyDataKeySrcAndDstProviders() + { + $providers = ['aws', 'azure', 'gcp', 'kmip', 'local']; + + foreach ($providers as $srcProvider) { + foreach ($providers as $dstProvider) { + yield [$srcProvider, $dstProvider]; + } + } + } + private function createInt64(string $value): Int64 { $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value); diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 7ac1b81f8..39e3f5d1f 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -4,15 +4,19 @@ use LogicException; use MongoDB\Client; +use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\ServerApi; use MongoDB\Model\BSONArray; use MongoDB\Tests\FunctionalTestCase; +use MongoDB\Tests\SpecTests\ClientSideEncryptionSpecTest; +use PHPUnit\Framework\Assert; use stdClass; use function array_key_exists; use function array_map; use function current; use function explode; +use function getenv; use function key; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertCount; @@ -24,6 +28,7 @@ use function PHPUnit\Framework\assertNotEmpty; use function PHPUnit\Framework\assertNotSame; use function PHPUnit\Framework\assertSame; +use function sprintf; /** * Execution context for spec tests. @@ -108,6 +113,10 @@ public function createEntities(array $entities): void $this->createClient($id, $def); break; + case 'clientEncryption': + $this->createClientEncryption($id, $def); + break; + case 'database': $this->createDatabase($id, $def); break; @@ -316,6 +325,79 @@ private function createClient(string $id, stdClass $o): void $this->entityMap->set($id, FunctionalTestCase::createTestClient($uri, $uriOptions, $driverOptions)); } + private function createClientEncryption(string $id, stdClass $o): void + { + Util::assertHasOnlyKeys($o, [ + 'id', + 'clientEncryptionOpts', + ]); + + $clientEncryptionOpts = []; + $clientId = null; + + if (isset($o->clientEncryptionOpts)) { + assertIsObject($o->clientEncryptionOpts); + $clientEncryptionOpts = (array) $o->clientEncryptionOpts; + } + + if (isset($clientEncryptionOpts['keyVaultClient'])) { + assertIsString($clientEncryptionOpts['keyVaultClient']); + /* Record the keyVaultClient's ID, which we'll later use to track + * the parent client in the entity map. */ + $clientId = $clientEncryptionOpts['keyVaultClient']; + $clientEncryptionOpts['keyVaultClient'] = $this->entityMap->getClient($clientId)->getManager(); + } + + if (isset($clientEncryptionOpts['kmsProviders'])) { + assertIsObject($clientEncryptionOpts['kmsProviders']); + + if (isset($clientEncryptionOpts['kmsProviders']->aws->accessKeyId->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->aws->accessKeyId = static::getEnv('AWS_ACCESS_KEY_ID'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->aws->secretAccessKey->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->aws->secretAccessKey = static::getEnv('AWS_SECRET_ACCESS_KEY'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->azure->clientId->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->azure->clientId = static::getEnv('AZURE_CLIENT_ID'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->azure->clientSecret->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->azure->clientSecret = static::getEnv('AZURE_CLIENT_SECRET'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->azure->tenantId->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->azure->tenantId = static::getEnv('AZURE_TENANT_ID'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->gcp->email->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->gcp->email = static::getEnv('GCP_EMAIL'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->gcp->privateKey->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->gcp->privateKey = static::getEnv('GCP_PRIVATE_KEY'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->kmip->endpoint->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->kmip->endpoint = static::getEnv('KMIP_ENDPOINT'); + } + + if (isset($clientEncryptionOpts['kmsProviders']->local->key->{'$$placeholder'})) { + $clientEncryptionOpts['kmsProviders']->local->key = ClientSideEncryptionSpecTest::LOCAL_MASTERKEY; + } + } + + if (isset($clientEncryptionOpts['kmsProviders']->kmip->endpoint)) { + $clientEncryptionOpts['tlsOptions']['kmip'] = [ + 'tlsCAFile' => static::getEnv('KMS_TLS_CA_FILE'), + 'tlsCertificateKeyFile' => static::getEnv('KMS_TLS_CERTIFICATE_KEY_FILE'), + ]; + } + + $this->entityMap->set($id, new ClientEncryption($clientEncryptionOpts), $clientId); + } + private function createEntityCollector(string $clientId, stdClass $o): void { Util::assertHasOnlyKeys($o, ['id', 'events']); @@ -411,6 +493,17 @@ private function createBucket(string $id, stdClass $o): void $this->entityMap->set($id, $database->selectGridFSBucket($options), $databaseId); } + private static function getEnv(string $name): string + { + $value = getenv($name); + + if ($value === false) { + Assert::markTestSkipped(sprintf('Environment variable "%s" is not defined', $name)); + } + + return $value; + } + private static function prepareCollectionOrDatabaseOptions(array $options): array { Util::assertHasOnlyKeys($options, ['readConcern', 'readPreference', 'writeConcern']); diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php index 1c05b23e0..3e50f574b 100644 --- a/tests/UnifiedSpecTests/EntityMap.php +++ b/tests/UnifiedSpecTests/EntityMap.php @@ -7,6 +7,7 @@ use MongoDB\Client; use MongoDB\Collection; use MongoDB\Database; +use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Cursor; use MongoDB\Driver\Session; use MongoDB\GridFS\Bucket; @@ -182,6 +183,7 @@ private static function isSupportedType(): Constraint if (self::$isSupportedType === null) { self::$isSupportedType = logicalOr( isInstanceOf(Client::class), + isInstanceOf(ClientEncryption::class), isInstanceOf(Database::class), isInstanceOf(Collection::class), isInstanceOf(Session::class), diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index d7b377a4e..ca13f32e5 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -8,6 +8,7 @@ use MongoDB\Client; use MongoDB\Collection; use MongoDB\Database; +use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Cursor; use MongoDB\Driver\Server; use MongoDB\Driver\Session; @@ -186,6 +187,9 @@ private function execute() case Client::class: $result = $this->executeForClient($object); break; + case ClientEncryption::class: + $result = $this->executeForClientEncryption($object); + break; case Database::class: $result = $this->executeForDatabase($object); break; @@ -275,6 +279,61 @@ function (DatabaseInfo $info) { } } + private function executeForClientEncryption(ClientEncryption $clientEncryption) + { + $args = $this->prepareArguments(); + Util::assertArgumentsBySchema(ClientEncryption::class, $this->name, $args); + + switch ($this->name) { + case 'addKeyAltName': + assertArrayHasKey('id', $args); + assertArrayHasKey('keyAltName', $args); + + return $clientEncryption->addKeyAltName($args['id'], $args['keyAltName']); + + case 'createDataKey': + assertArrayHasKey('kmsProvider', $args); + // CSFLE spec tests nest options under an "opts" key (see: DRIVERS-2414) + $options = array_key_exists('opts', $args) ? (array) $args['opts'] : []; + + return $clientEncryption->createDataKey($args['kmsProvider'], $options); + + case 'deleteKey': + assertArrayHasKey('id', $args); + + return $clientEncryption->deleteKey($args['id']); + + case 'getKey': + assertArrayHasKey('id', $args); + + return $clientEncryption->getKey($args['id']); + + case 'getKeyByAltName': + assertArrayHasKey('keyAltName', $args); + + return $clientEncryption->getKeyByAltName($args['keyAltName']); + + case 'getKeys': + return iterator_to_array($clientEncryption->getKeys()); + + case 'removeKeyAltName': + assertArrayHasKey('id', $args); + assertArrayHasKey('keyAltName', $args); + + return $clientEncryption->removeKeyAltName($args['id'], $args['keyAltName']); + + case 'rewrapManyDataKey': + assertArrayHasKey('filter', $args); + // CSFLE spec tests nest options under an "opts" key (see: DRIVERS-2414) + $options = array_key_exists('opts', $args) ? (array) $args['opts'] : []; + + return static::prepareRewrapManyDataKeyResult($clientEncryption->rewrapManyDataKey($args['filter'], $options)); + + default: + Assert::fail('Unsupported clientEncryption operation: ' . $this->name); + } + } + private function executeForCollection(Collection $collection) { $args = $this->prepareArguments(); @@ -933,6 +992,31 @@ private static function prepareBulkWriteRequest(stdClass $request): array } } + /** + * ClientEncryption::rewrapManyDataKey() returns its result as a raw BSON + * document and does not utilize WriteResult because getServer() cannot be + * implemented. To satisfy result expectations, unset bulkWriteResult if it + * is null and rename its fields (per the CRUD spec) otherwise. */ + private static function prepareRewrapManyDataKeyResult(stdClass $result): object + { + if ($result->bulkWriteResult === null) { + unset($result->bulkWriteResult); + + return $result; + } + + $result->bulkWriteResult = [ + 'insertedCount' => $result->bulkWriteResult->nInserted, + 'matchedCount' => $result->bulkWriteResult->nMatched, + 'modifiedCount' => $result->bulkWriteResult->nModified, + 'deletedCount' => $result->bulkWriteResult->nRemoved, + 'upsertedCount' => $result->bulkWriteResult->nUpserted, + 'upsertedIds' => $result->bulkWriteResult->upserted ?? new stdClass(), + ]; + + return $result; + } + private static function prepareUploadArguments(array $args): array { $source = $args['source'] ?? null; diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index 17eb7826e..d3d6d641f 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -49,6 +49,9 @@ class RunOnRequirement /** @var string */ private $serverless; + /** @var bool */ + private $csfle; + /** @var array */ private static $supportedTopologies = [ self::TOPOLOGY_SINGLE, @@ -67,7 +70,7 @@ class RunOnRequirement public function __construct(stdClass $o) { - Util::assertHasOnlyKeys($o, ['minServerVersion', 'maxServerVersion', 'topologies', 'serverParameters', 'auth', 'serverless']); + Util::assertHasOnlyKeys($o, ['minServerVersion', 'maxServerVersion', 'topologies', 'serverParameters', 'auth', 'serverless', 'csfle']); if (isset($o->minServerVersion)) { assertIsString($o->minServerVersion); @@ -103,9 +106,14 @@ public function __construct(stdClass $o) assertContains($o->serverless, self::$supportedServerless); $this->serverless = $o->serverless; } + + if (isset($o->csfle)) { + assertIsBool($o->csfle); + $this->csfle = $o->csfle; + } } - public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated, bool $isServerless): bool + public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated, bool $isServerless, bool $isClientSideEncryptionSupported): bool { if (isset($this->minServerVersion) && version_compare($serverVersion, $this->minServerVersion, '<')) { return false; @@ -140,6 +148,10 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s } } + if (isset($this->csfle) && $isClientSideEncryptionSupported !== $this->csfle) { + return false; + } + return true; } diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index ada9f426d..9caf782dd 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -59,6 +59,11 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/entity-client-cmap-events: events are captured during an operation' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType can be set to command and cmap' => 'PHPC does not implement CMAP', 'valid-pass/expectedEventsForClient-eventType: eventType defaults to command if unset' => 'PHPC does not implement CMAP', + // CSOT is not yet implemented + 'valid-pass/collectionData-createOptions: collection is created with the correct options' => 'CSOT is not yet implemented (PHPC-1760)', + 'valid-pass/createEntities-operation: createEntities operation' => 'CSOT is not yet implemented (PHPC-1760)', + 'valid-pass/entity-cursor-iterateOnce: iterateOnce' => 'CSOT is not yet implemented (PHPC-1760)', + 'valid-pass/matches-lte-operator: special lte matching operator' => 'CSOT is not yet implemented (PHPC-1760)', ]; /** @var UnifiedTestRunner */ @@ -95,6 +100,19 @@ public function provideChangeStreamsTests() return $this->provideTests(__DIR__ . '/change-streams/*.json'); } + /** + * @dataProvider provideClientSideEncryptionTests + */ + public function testClientSideEncryption(UnifiedTestCase $test): void + { + self::$runner->run($test); + } + + public function provideClientSideEncryptionTests() + { + return $this->provideTests(__DIR__ . '/client-side-encryption/*.json'); + } + /** * @dataProvider provideCollectionManagementTests */ @@ -230,6 +248,11 @@ public function testFailingTests(UnifiedTestCase $test): void try { self::$runner->run($test); } catch (Exception $e) { + // Respect skipped tests (e.g. evaluated runOnRequirements) + if ($e instanceof SkippedTest) { + throw $e; + } + /* As is done in PHPUnit\Framework\TestCase::runBare(), exceptions * other than a select few will indicate a test failure. We cannot * call TestCase::hasFailed() because runBare() has yet to catch the @@ -238,7 +261,7 @@ public function testFailingTests(UnifiedTestCase $test): void * IncompleteTest is intentionally omitted as it is thrown for an * incompatible schema. This differs from PHPUnit's internal logic. */ - $failed = ! ($e instanceof SkippedTest || $e instanceof Warning); + $failed = ! ($e instanceof Warning); } // phpcs:enable diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index a378f7996..878797e16 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -25,6 +25,8 @@ use function getenv; use function implode; use function in_array; +use function is_executable; +use function is_readable; use function is_string; use function parse_url; use function PHPUnit\Framework\assertContainsOnly; @@ -43,7 +45,9 @@ use function substr_replace; use function version_compare; +use const DIRECTORY_SEPARATOR; use const FILTER_VALIDATE_BOOLEAN; +use const PATH_SEPARATOR; use const PHP_URL_HOST; /** @@ -60,7 +64,7 @@ final class UnifiedTestRunner public const MIN_SCHEMA_VERSION = '1.0'; - public const MAX_SCHEMA_VERSION = '1.7'; + public const MAX_SCHEMA_VERSION = '1.8'; /** @var MongoDB\Client */ private $internalClient; @@ -247,6 +251,7 @@ private function checkRunOnRequirements(array $runOnRequirements): void $this->getServerParameters(), $this->isAuthenticated(), $this->isServerless(), + $this->isClientSideEncryptionSupported(), ]; } @@ -349,6 +354,48 @@ private function isAuthenticated(): bool throw new UnexpectedValueException('Could not determine authentication status'); } + /** + * Return whether client-side encryption is supported. + */ + private function isClientSideEncryptionSupported(): bool + { + /* CSFLE technically requires FCV 4.2+ but this is sufficient since we + * do not test on mixed-version clusters. */ + if (version_compare($this->getServerVersion(), '4.2', '<')) { + return false; + } + + if (FunctionalTestCase::getModuleInfo('libmongocrypt') === 'disabled') { + return false; + } + + return static::isCryptSharedLibAvailable() || static::isMongocryptdAvailable(); + } + + private static function isCryptSharedLibAvailable(): bool + { + $cryptSharedLibPath = getenv('CRYPT_SHARED_LIB_PATH'); + + if ($cryptSharedLibPath === false) { + return false; + } + + return is_readable($cryptSharedLibPath); + } + + private static function isMongocryptdAvailable(): bool + { + $paths = explode(PATH_SEPARATOR, getenv("PATH")); + + foreach ($paths as $path) { + if (is_executable($path . DIRECTORY_SEPARATOR . 'mongocryptd')) { + return true; + } + } + + return false; + } + /** * Return whether serverless (i.e. proxy as mongos) is being utilized. */ diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index d9a2c347f..1572e16d4 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -6,6 +6,7 @@ use MongoDB\Client; use MongoDB\Collection; use MongoDB\Database; +use MongoDB\Driver\ClientEncryption; use MongoDB\Driver\Cursor; use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadPreference; @@ -59,6 +60,16 @@ final class Util 'listDatabaseNames' => ['authorizedDatabases', 'filter', 'maxTimeMS', 'session'], 'listDatabases' => ['authorizedDatabases', 'filter', 'maxTimeMS', 'session'], ], + ClientEncryption::class => [ + 'addKeyAltName' => ['id', 'keyAltName'], + 'createDataKey' => ['kmsProvider', 'opts'], + 'deleteKey' => ['id'], + 'getKey' => ['id'], + 'getKeyByAltName' => ['keyAltName'], + 'getKeys' => [], + 'removeKeyAltName' => ['id', 'keyAltName'], + 'rewrapManyDataKey' => ['filter', 'opts'], + ], Database::class => [ 'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'], 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'showExpandedEvents'], diff --git a/tests/UnifiedSpecTests/client-side-encryption/addKeyAltName.json b/tests/UnifiedSpecTests/client-side-encryption/addKeyAltName.json new file mode 100644 index 000000000..f70bc572a --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/addKeyAltName.json @@ -0,0 +1,609 @@ +{ + "description": "addKeyAltName", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "add keyAltName to non-existent data key", + "operations": [ + { + "name": "addKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "AAAjYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "new_key_alt_name" + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "AAAjYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": { + "$addToSet": { + "keyAltNames": "new_key_alt_name" + } + }, + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ] + }, + { + "description": "add new keyAltName to data key with no keyAltNames", + "operations": [ + { + "name": "addKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "local_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "projection": { + "_id": 0, + "keyAltNames": 1 + } + }, + "expectResult": [ + { + "keyAltNames": [ + "local_key" + ] + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": { + "$addToSet": { + "keyAltNames": "local_key" + } + }, + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "add existing keyAltName to existing data key", + "operations": [ + { + "name": "addKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "local_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "addKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "local_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "projection": { + "_id": 0, + "keyAltNames": 1 + } + }, + "expectResult": [ + { + "keyAltNames": [ + "local_key" + ] + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": { + "$addToSet": { + "keyAltNames": "local_key" + } + }, + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": { + "$addToSet": { + "keyAltNames": "local_key" + } + }, + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "add new keyAltName to data key with keyAltNames", + "operations": [ + { + "name": "addKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "local_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "addKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "another_name" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "_id": 0, + "keyAltNames": "$keyAltNames" + } + }, + { + "$unwind": "$keyAltNames" + }, + { + "$sort": { + "keyAltNames": 1 + } + } + ] + }, + "expectResult": [ + { + "keyAltNames": "another_name" + }, + { + "keyAltNames": "local_key" + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": { + "$addToSet": { + "keyAltNames": "local_key" + } + }, + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": { + "$addToSet": { + "keyAltNames": "another_name" + } + }, + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/createDataKey-kms_providers-invalid.json b/tests/UnifiedSpecTests/client-side-encryption/createDataKey-kms_providers-invalid.json new file mode 100644 index 000000000..2344a61a9 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/createDataKey-kms_providers-invalid.json @@ -0,0 +1,119 @@ +{ + "description": "createDataKey-kms_providers-invalid", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent", + "commandSucceededEvent", + "commandFailedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": { + "$$placeholder": 1 + }, + "secretAccessKey": { + "$$placeholder": 1 + } + } + } + } + } + } + ], + "tests": [ + { + "description": "create data key without required master key fields", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "aws", + "opts": { + "masterKey": {} + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "create data key with invalid master key field", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "masterKey": { + "invalid": 1 + } + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + }, + { + "description": "create data key with invalid master key", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "aws", + "opts": { + "masterKey": { + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "invalid" + } + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/createDataKey.json b/tests/UnifiedSpecTests/client-side-encryption/createDataKey.json new file mode 100644 index 000000000..110c726f9 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/createDataKey.json @@ -0,0 +1,711 @@ +{ + "description": "createDataKey", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": { + "$$placeholder": 1 + }, + "secretAccessKey": { + "$$placeholder": 1 + } + }, + "azure": { + "tenantId": { + "$$placeholder": 1 + }, + "clientId": { + "$$placeholder": 1 + }, + "clientSecret": { + "$$placeholder": 1 + } + }, + "gcp": { + "email": { + "$$placeholder": 1 + }, + "privateKey": { + "$$placeholder": 1 + } + }, + "kmip": { + "endpoint": { + "$$placeholder": 1 + } + }, + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [] + } + ], + "tests": [ + { + "description": "create data key with AWS KMS provider", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "aws", + "opts": { + "masterKey": { + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + } + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$exists": true + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with Azure KMS provider", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "azure", + "opts": { + "masterKey": { + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + } + } + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$exists": true + }, + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with GCP KMS provider", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "gcp", + "opts": { + "masterKey": { + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + } + } + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$exists": true + }, + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with KMIP KMS provider", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "kmip" + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$exists": true + }, + "masterKey": { + "provider": "kmip", + "keyId": { + "$$type": "string" + } + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with local KMS provider", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local" + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$exists": true + }, + "masterKey": { + "provider": "local" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with no keyAltName", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "keyAltNames": [] + } + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyAltNames": { + "$$exists": false + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with single keyAltName", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "keyAltNames": [ + "local_key" + ] + } + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with multiple keyAltNames", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "keyAltNames": [ + "abc", + "def" + ] + } + }, + "expectResult": { + "$$type": "binData" + } + }, + { + "name": "aggregate", + "object": "collection0", + "arguments": { + "pipeline": [ + { + "$project": { + "_id": 0, + "keyAltNames": 1 + } + }, + { + "$unwind": "$keyAltNames" + }, + { + "$sort": { + "keyAltNames": 1 + } + } + ] + }, + "expectResult": [ + { + "keyAltNames": "abc" + }, + { + "keyAltNames": "def" + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyAltNames": { + "$$type": "array" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "aggregate" + } + } + ] + } + ] + }, + { + "description": "create datakey with custom key material", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "keyMaterial": { + "$binary": { + "base64": "a2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFs", + "subType": "00" + } + } + } + }, + "expectResult": { + "$$type": "binData" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "insert": "datakeys", + "documents": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "create datakey with invalid custom key material (too short)", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "keyMaterial": { + "$binary": { + "base64": "a2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFsa2V5X21hdGVyaWFs", + "subType": "00" + } + } + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/deleteKey.json b/tests/UnifiedSpecTests/client-side-encryption/deleteKey.json new file mode 100644 index 000000000..3a10fb082 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/deleteKey.json @@ -0,0 +1,557 @@ +{ + "description": "deleteKey", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + }, + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "delete non-existent data key", + "operations": [ + { + "name": "deleteKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "AAAzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "expectResult": { + "deletedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "delete": "datakeys", + "deletes": [ + { + "q": { + "_id": { + "$binary": { + "base64": "AAAzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "limit": 1 + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + }, + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ] + }, + { + "description": "delete existing AWS data key", + "operations": [ + { + "name": "deleteKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "delete": "datakeys", + "deletes": [ + { + "q": { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "limit": 1 + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ] + }, + { + "description": "delete existing local data key", + "operations": [ + { + "name": "deleteKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "expectResult": { + "deletedCount": 1 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "delete": "datakeys", + "deletes": [ + { + "q": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "limit": 1 + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + } + ] + } + ] + }, + { + "description": "delete existing data key twice", + "operations": [ + { + "name": "deleteKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "expectResult": { + "deletedCount": 1 + } + }, + { + "name": "deleteKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "expectResult": { + "deletedCount": 0 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "delete": "datakeys", + "deletes": [ + { + "q": { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "limit": 1 + } + ], + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "delete": "datakeys", + "deletes": [ + { + "q": { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "limit": 1 + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/getKey.json b/tests/UnifiedSpecTests/client-side-encryption/getKey.json new file mode 100644 index 000000000..2ea3fe735 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/getKey.json @@ -0,0 +1,319 @@ +{ + "description": "getKey", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + }, + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "get non-existent data key", + "operations": [ + { + "name": "getKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "AAAzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "_id": { + "$binary": { + "base64": "AAAzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "get existing AWS data key", + "operations": [ + { + "name": "getKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + } + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "get existing local data key", + "operations": [ + { + "name": "getKey", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/getKeyByAltName.json b/tests/UnifiedSpecTests/client-side-encryption/getKeyByAltName.json new file mode 100644 index 000000000..2505abc16 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/getKeyByAltName.json @@ -0,0 +1,289 @@ +{ + "description": "getKeyByAltName", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + }, + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "get non-existent data key", + "operations": [ + { + "name": "getKeyByAltName", + "object": "clientEncryption0", + "arguments": { + "keyAltName": "does_not_exist" + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": "does_not_exist" + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "get existing AWS data key", + "operations": [ + { + "name": "getKeyByAltName", + "object": "clientEncryption0", + "arguments": { + "keyAltName": "aws_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": "aws_key" + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "get existing local data key", + "operations": [ + { + "name": "getKeyByAltName", + "object": "clientEncryption0", + "arguments": { + "keyAltName": "local_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": "local_key" + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/getKeys.json b/tests/UnifiedSpecTests/client-side-encryption/getKeys.json new file mode 100644 index 000000000..d94471235 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/getKeys.json @@ -0,0 +1,260 @@ +{ + "description": "getKeys", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [] + } + ], + "tests": [ + { + "description": "getKeys with zero key documents", + "operations": [ + { + "name": "getKeys", + "object": "clientEncryption0", + "expectResult": [] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "getKeys with single key documents", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local", + "opts": { + "keyAltNames": [ + "abc" + ] + } + }, + "expectResult": { + "$$type": "binData" + } + }, + { + "name": "getKeys", + "object": "clientEncryption0", + "expectResult": [ + { + "_id": { + "$$type": "binData" + }, + "keyAltNames": [ + "abc" + ], + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "getKeys with many key documents", + "operations": [ + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local" + }, + "expectResult": { + "$$type": "binData" + } + }, + { + "name": "createDataKey", + "object": "clientEncryption0", + "arguments": { + "kmsProvider": "local" + }, + "expectResult": { + "$$type": "binData" + } + }, + { + "name": "getKeys", + "object": "clientEncryption0", + "expectResult": [ + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + }, + { + "_id": { + "$$type": "binData" + }, + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": { + "$$type": "int" + }, + "masterKey": { + "$$type": "object" + } + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "commandName": "insert" + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/removeKeyAltName.json b/tests/UnifiedSpecTests/client-side-encryption/removeKeyAltName.json new file mode 100644 index 000000000..1b7077077 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/removeKeyAltName.json @@ -0,0 +1,672 @@ +{ + "description": "removeKeyAltName", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "alternate_name", + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "remove keyAltName from non-existent data key", + "operations": [ + { + "name": "removeKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "AAAjYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "does_not_exist" + }, + "expectResult": { + "$$unsetOrMatches": null + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "AAAjYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": [ + { + "$set": { + "keyAltNames": { + "$cond": [ + { + "$eq": [ + "$keyAltNames", + [ + "does_not_exist" + ] + ] + }, + "$$REMOVE", + { + "$filter": { + "input": "$keyAltNames", + "cond": { + "$ne": [ + "$$this", + "does_not_exist" + ] + } + } + } + ] + } + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "alternate_name", + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ] + }, + { + "description": "remove non-existent keyAltName from existing data key", + "operations": [ + { + "name": "removeKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "does_not_exist" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "alternate_name", + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": [ + { + "$set": { + "keyAltNames": { + "$cond": [ + { + "$eq": [ + "$keyAltNames", + [ + "does_not_exist" + ] + ] + }, + "$$REMOVE", + { + "$filter": { + "input": "$keyAltNames", + "cond": { + "$ne": [ + "$$this", + "does_not_exist" + ] + } + } + } + ] + } + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "datakeys", + "databaseName": "keyvault", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "alternate_name", + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ] + }, + { + "description": "remove an existing keyAltName from an existing data key", + "operations": [ + { + "name": "removeKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "alternate_name" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "alternate_name", + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "projection": { + "_id": 0, + "keyAltNames": 1 + } + }, + "expectResult": [ + { + "keyAltNames": [ + "local_key" + ] + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": [ + { + "$set": { + "keyAltNames": { + "$cond": [ + { + "$eq": [ + "$keyAltNames", + [ + "alternate_name" + ] + ] + }, + "$$REMOVE", + { + "$filter": { + "input": "$keyAltNames", + "cond": { + "$ne": [ + "$$this", + "alternate_name" + ] + } + } + } + ] + } + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + } + ] + } + ] + }, + { + "description": "remove the last keyAltName from an existing data key", + "operations": [ + { + "name": "removeKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "alternate_name" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "alternate_name", + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + }, + { + "name": "removeKeyAltName", + "object": "clientEncryption0", + "arguments": { + "id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltName": "local_key" + }, + "expectResult": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$$type": "binData" + }, + "creationDate": { + "$$type": "date" + }, + "updateDate": { + "$$type": "date" + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": [ + { + "$set": { + "keyAltNames": { + "$cond": [ + { + "$eq": [ + "$keyAltNames", + [ + "alternate_name" + ] + ] + }, + "$$REMOVE", + { + "$filter": { + "input": "$keyAltNames", + "cond": { + "$ne": [ + "$$this", + "alternate_name" + ] + } + } + } + ] + } + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "findAndModify": "datakeys", + "query": { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + } + }, + "update": [ + { + "$set": { + "keyAltNames": { + "$cond": [ + { + "$eq": [ + "$keyAltNames", + [ + "local_key" + ] + ] + }, + "$$REMOVE", + { + "$filter": { + "input": "$keyAltNames", + "cond": { + "$ne": [ + "$$this", + "local_key" + ] + } + } + } + ] + } + } + } + ] + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-decrypt_failure.json b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-decrypt_failure.json new file mode 100644 index 000000000..4c7d4e804 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-decrypt_failure.json @@ -0,0 +1,162 @@ +{ + "description": "rewrapManyDataKey-decrypt_failure", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": { + "$$placeholder": 1 + }, + "secretAccessKey": { + "$$placeholder": 1 + } + }, + "azure": { + "tenantId": { + "$$placeholder": 1 + }, + "clientId": { + "$$placeholder": 1 + }, + "clientSecret": { + "$$placeholder": 1 + } + }, + "gcp": { + "email": { + "$$placeholder": 1 + }, + "privateKey": { + "$$placeholder": 1 + } + }, + "kmip": { + "endpoint": { + "$$placeholder": 1 + } + }, + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-2:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-2" + } + } + ] + } + ], + "tests": [ + { + "description": "rewrap data key that fails during decryption due to invalid masterKey", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": {}, + "opts": { + "provider": "local" + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find", + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-encrypt_failure.json b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-encrypt_failure.json new file mode 100644 index 000000000..cd2d20c25 --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey-encrypt_failure.json @@ -0,0 +1,250 @@ +{ + "description": "rewrapManyDataKey-encrypt_failure", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": { + "$$placeholder": 1 + }, + "secretAccessKey": { + "$$placeholder": 1 + } + }, + "azure": { + "tenantId": { + "$$placeholder": 1 + }, + "clientId": { + "$$placeholder": 1 + }, + "clientSecret": { + "$$placeholder": 1 + } + }, + "gcp": { + "email": { + "$$placeholder": 1 + }, + "privateKey": { + "$$placeholder": 1 + } + }, + "kmip": { + "endpoint": { + "$$placeholder": 1 + } + }, + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "rewrap with invalid masterKey for AWS KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": {}, + "opts": { + "provider": "aws", + "masterKey": { + "key": "arn:aws:kms:us-east-2:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-2" + } + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find", + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with invalid masterKey for Azure KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": {}, + "opts": { + "provider": "azure", + "masterKey": { + "keyVaultEndpoint": "invalid-vault-csfle.vault.azure.net", + "keyName": "invalid-name-csfle" + } + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find", + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with invalid masterKey for GCP KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": {}, + "opts": { + "provider": "gcp", + "masterKey": { + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "invalid-ring-csfle", + "keyName": "invalid-name-csfle" + } + } + }, + "expectError": { + "isClientError": true + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "commandName": "find", + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json new file mode 100644 index 000000000..89860de0c --- /dev/null +++ b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json @@ -0,0 +1,1475 @@ +{ + "description": "rewrapManyDataKey", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": { + "$$placeholder": 1 + }, + "secretAccessKey": { + "$$placeholder": 1 + } + }, + "azure": { + "tenantId": { + "$$placeholder": 1 + }, + "clientId": { + "$$placeholder": 1 + }, + "clientSecret": { + "$$placeholder": 1 + } + }, + "gcp": { + "email": { + "$$placeholder": 1 + }, + "privateKey": { + "$$placeholder": 1 + } + }, + "kmip": { + "endpoint": { + "$$placeholder": 1 + } + }, + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "aws_key" + ], + "keyMaterial": { + "$binary": { + "base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gFXJqbF0Fy872MD7xl56D/2AAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDO7HPisPUlGzaio9vgIBEIB7/Qow46PMh/8JbEUbdXgTGhLfXPE+KIVW7T8s6YEMlGiRvMu7TV0QCIUJlSHPKZxzlJ2iwuz5yXeOag+EdY+eIQ0RKrsJ3b8UTisZYzGjfzZnxUKLzLoeXremtRCm3x47wCuHKd1dhh6FBbYt5TL2tDaj+vL2GBrKat2L", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + }, + { + "_id": { + "$binary": { + "base64": "YXp1cmVhenVyZWF6dXJlYQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "azure_key" + ], + "keyMaterial": { + "$binary": { + "base64": "pr01l7qDygUkFE/0peFwpnNlv3iIy8zrQK38Q9i12UCN2jwZHDmfyx8wokiIKMb9kAleeY+vnt3Cf1MKu9kcDmI+KxbNDd+V3ytAAGzOVLDJr77CiWjF9f8ntkXRHrAY9WwnVDANYkDwXlyU0Y2GQFTiW65jiQhUtYLYH63Tk48SsJuQvnWw1Q+PzY8ga+QeVec8wbcThwtm+r2IHsCFnc72Gv73qq7weISw+O4mN08z3wOp5FOS2ZM3MK7tBGmPdBcktW7F8ODGsOQ1FU53OrWUnyX2aTi2ftFFFMWVHqQo7EYuBZHru8RRODNKMyQk0BFfKovAeTAVRv9WH9QU7g==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + } + }, + { + "_id": { + "$binary": { + "base64": "Z2NwZ2NwZ2NwZ2NwZ2NwZw==", + "subType": "04" + } + }, + "keyAltNames": [ + "gcp_key" + ], + "keyMaterial": { + "$binary": { + "base64": "CiQAIgLj0USbQtof/pYRLQO96yg/JEtZbD1UxKueaC37yzT5tTkSiQEAhClWB5ZCSgzHgxv8raWjNB4r7e8ePGdsmSuYTYmLC5oHHS/BdQisConzNKFaobEQZHamTCjyhy5NotKF8MWoo+dyfQApwI29+vAGyrUIQCXzKwRnNdNQ+lb3vJtS5bqvLTvSxKHpVca2kqyC9nhonV+u4qru5Q2bAqUgVFc8fL4pBuvlowZFTQ==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + } + }, + { + "_id": { + "$binary": { + "base64": "a21pcGttaXBrbWlwa21pcA==", + "subType": "04" + } + }, + "keyAltNames": [ + "kmip_key" + ], + "keyMaterial": { + "$binary": { + "base64": "CklVctHzke4mcytd0TxGqvepkdkQN8NUF4+jV7aZQITAKdz6WjdDpq3lMt9nSzWGG2vAEfvRb3mFEVjV57qqGqxjq2751gmiMRHXz0btStbIK3mQ5xbY9kdye4tsixlCryEwQONr96gwlwKKI9Nubl9/8+uRF6tgYjje7Q7OjauEf1SrJwKcoQ3WwnjZmEqAug0kImCpJ/irhdqPzivRiA==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "kmip", + "keyId": "1" + } + }, + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "keyAltNames": [ + "local_key" + ], + "keyMaterial": { + "$binary": { + "base64": "ABKBldDEoDW323yejOnIRk6YQmlD9d3eQthd16scKL75nz2LjNL9fgPDZWrFFOlqlhMCFaSrNJfGrFUjYk5JFDO7soG5Syb50k1niJoKg4ilsj0L4mpimFUtTpOr2nzZOeQtvAksEXc7gsFgq8gV7t/U3lsaXPY7I0t42DfSE8EGlPdxRjFdHnxh+OR8h7U9b8Qs5K5UuhgyeyxaBZ1Hgw==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1641024000000" + } + }, + "status": 1, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "no keys to rewrap due to no filter matches", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": { + "keyAltNames": "no_matching_keys" + }, + "opts": { + "provider": "local" + } + }, + "expectResult": { + "bulkWriteResult": { + "$$exists": false + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": "no_matching_keys" + }, + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with new AWS KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": { + "keyAltNames": { + "$ne": "aws_key" + } + }, + "opts": { + "provider": "aws", + "masterKey": { + "key": "arn:aws:kms:us-east-1:579766882180:key/061334ae-07a8-4ceb-a813-8135540e837d", + "region": "us-east-1" + } + } + }, + "expectResult": { + "bulkWriteResult": { + "insertedCount": 0, + "matchedCount": 4, + "modifiedCount": 4, + "deletedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": { + "$ne": "aws_key" + } + }, + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "update": "datakeys", + "ordered": true, + "updates": [ + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/061334ae-07a8-4ceb-a813-8135540e837d", + "region": "us-east-1" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/061334ae-07a8-4ceb-a813-8135540e837d", + "region": "us-east-1" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/061334ae-07a8-4ceb-a813-8135540e837d", + "region": "us-east-1" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/061334ae-07a8-4ceb-a813-8135540e837d", + "region": "us-east-1" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with new Azure KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": { + "keyAltNames": { + "$ne": "azure_key" + } + }, + "opts": { + "provider": "azure", + "masterKey": { + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + } + } + }, + "expectResult": { + "bulkWriteResult": { + "insertedCount": 0, + "matchedCount": 4, + "modifiedCount": 4, + "deletedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": { + "$ne": "azure_key" + } + }, + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "update": "datakeys", + "ordered": true, + "updates": [ + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with new GCP KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": { + "keyAltNames": { + "$ne": "gcp_key" + } + }, + "opts": { + "provider": "gcp", + "masterKey": { + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + } + } + }, + "expectResult": { + "bulkWriteResult": { + "insertedCount": 0, + "matchedCount": 4, + "modifiedCount": 4, + "deletedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": { + "$ne": "gcp_key" + } + }, + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "update": "datakeys", + "ordered": true, + "updates": [ + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with new KMIP KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": { + "keyAltNames": { + "$ne": "kmip_key" + } + }, + "opts": { + "provider": "kmip" + } + }, + "expectResult": { + "bulkWriteResult": { + "insertedCount": 0, + "matchedCount": 4, + "modifiedCount": 4, + "deletedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": { + "$ne": "kmip_key" + } + }, + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "update": "datakeys", + "ordered": true, + "updates": [ + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "kmip", + "keyId": { + "$$type": "string" + } + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "kmip", + "keyId": { + "$$type": "string" + } + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "kmip", + "keyId": { + "$$type": "string" + } + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "kmip", + "keyId": { + "$$type": "string" + } + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with new local KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": { + "keyAltNames": { + "$ne": "local_key" + } + }, + "opts": { + "provider": "local" + } + }, + "expectResult": { + "bulkWriteResult": { + "insertedCount": 0, + "matchedCount": 4, + "modifiedCount": 4, + "deletedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": { + "keyAltNames": { + "$ne": "local_key" + } + }, + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "update": "datakeys", + "ordered": true, + "updates": [ + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "local" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "local" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "local" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "provider": "local" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + } + ] + } + ] + }, + { + "description": "rewrap with current KMS provider", + "operations": [ + { + "name": "rewrapManyDataKey", + "object": "clientEncryption0", + "arguments": { + "filter": {} + }, + "expectResult": { + "bulkWriteResult": { + "insertedCount": 0, + "matchedCount": 5, + "modifiedCount": 5, + "deletedCount": 0, + "upsertedCount": 0, + "upsertedIds": {} + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "projection": { + "masterKey": 1 + }, + "sort": { + "keyAltNames": 1 + } + }, + "expectResult": [ + { + "_id": { + "$binary": { + "base64": "YXdzYXdzYXdzYXdzYXdzYQ==", + "subType": "04" + } + }, + "masterKey": { + "provider": "aws", + "key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0", + "region": "us-east-1" + } + }, + { + "_id": { + "$binary": { + "base64": "YXp1cmVhenVyZWF6dXJlYQ==", + "subType": "04" + } + }, + "masterKey": { + "provider": "azure", + "keyVaultEndpoint": "key-vault-csfle.vault.azure.net", + "keyName": "key-name-csfle" + } + }, + { + "_id": { + "$binary": { + "base64": "Z2NwZ2NwZ2NwZ2NwZ2NwZw==", + "subType": "04" + } + }, + "masterKey": { + "provider": "gcp", + "projectId": "devprod-drivers", + "location": "global", + "keyRing": "key-ring-csfle", + "keyName": "key-name-csfle" + } + }, + { + "_id": { + "$binary": { + "base64": "a21pcGttaXBrbWlwa21pcA==", + "subType": "04" + } + }, + "masterKey": { + "provider": "kmip", + "keyId": "1" + } + }, + { + "_id": { + "$binary": { + "base64": "bG9jYWxrZXlsb2NhbGtleQ==", + "subType": "04" + } + }, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "find": "datakeys", + "filter": {}, + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "databaseName": "keyvault", + "command": { + "update": "datakeys", + "ordered": true, + "updates": [ + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "$$type": "object" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "$$type": "object" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "$$type": "object" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "$$type": "object" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + }, + { + "q": { + "_id": { + "$$type": "binData" + } + }, + "u": { + "$set": { + "masterKey": { + "$$type": "object" + }, + "keyMaterial": { + "$$type": "binData" + } + }, + "$currentDate": { + "updateDate": true + } + }, + "multi": { + "$$unsetOrMatches": false + }, + "upsert": { + "$$unsetOrMatches": false + } + } + ], + "writeConcern": { + "w": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "commandName": "find" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_aws_kms_credentials.json b/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_aws_kms_credentials.json new file mode 100644 index 000000000..e62de8003 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_aws_kms_credentials.json @@ -0,0 +1,36 @@ +{ + "description": "kmsProviders-missing_aws_kms_credentials", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": "accessKeyId" + } + } + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_azure_kms_credentials.json b/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_azure_kms_credentials.json new file mode 100644 index 000000000..8ef805d0f --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_azure_kms_credentials.json @@ -0,0 +1,36 @@ +{ + "description": "kmsProviders-missing_azure_kms_credentials", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "azure": { + "tenantId": "tenantId" + } + } + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_gcp_kms_credentials.json b/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_gcp_kms_credentials.json new file mode 100644 index 000000000..c6da1ce58 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/kmsProviders-missing_gcp_kms_credentials.json @@ -0,0 +1,36 @@ +{ + "description": "kmsProviders-missing_gcp_kms_credentials", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "gcp": { + "email": "email" + } + } + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-fail/kmsProviders-no_kms.json b/tests/UnifiedSpecTests/valid-fail/kmsProviders-no_kms.json new file mode 100644 index 000000000..57499b4ea --- /dev/null +++ b/tests/UnifiedSpecTests/valid-fail/kmsProviders-no_kms.json @@ -0,0 +1,32 @@ +{ + "description": "clientEncryptionOpts-no_kms", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": {} + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json b/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json new file mode 100644 index 000000000..64f8fb02f --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json @@ -0,0 +1,69 @@ +{ + "description": "collectionData-createOptions", + "schemaVersion": "1.9", + "runOnRequirements": [ + { + "minServerVersion": "3.6", + "serverless": "forbid" + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0", + "createOptions": { + "capped": true, + "size": 4096 + }, + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "collection is created with the correct options", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "collStats", + "command": { + "collStats": "coll0", + "scale": 1 + } + }, + "expectResult": { + "capped": true, + "maxSize": 4096 + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/createEntities-operation.json b/tests/UnifiedSpecTests/valid-pass/createEntities-operation.json new file mode 100644 index 000000000..3fde42919 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/createEntities-operation.json @@ -0,0 +1,74 @@ +{ + "description": "createEntities-operation", + "schemaVersion": "1.9", + "tests": [ + { + "description": "createEntities operation", + "operations": [ + { + "name": "createEntities", + "object": "testRunner", + "arguments": { + "entities": [ + { + "client": { + "id": "client1", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database1", + "client": "client1", + "databaseName": "database1" + } + }, + { + "collection": { + "id": "collection1", + "database": "database1", + "collectionName": "coll1" + } + } + ] + } + }, + { + "name": "deleteOne", + "object": "collection1", + "arguments": { + "filter": { + "_id": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client1", + "events": [ + { + "commandStartedEvent": { + "command": { + "delete": "coll1", + "deletes": [ + { + "q": { + "_id": 1 + }, + "limit": 1 + } + ] + }, + "commandName": "delete", + "databaseName": "database1" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json b/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json new file mode 100644 index 000000000..88fc28e34 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json @@ -0,0 +1,108 @@ +{ + "description": "entity-cursor-iterateOnce", + "schemaVersion": "1.9", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "databaseName": "database0", + "collectionName": "coll0", + "documents": [ + { + "_id": 1 + }, + { + "_id": 2 + }, + { + "_id": 3 + } + ] + } + ], + "tests": [ + { + "description": "iterateOnce", + "operations": [ + { + "name": "createFindCursor", + "object": "collection0", + "arguments": { + "filter": {}, + "batchSize": 2 + }, + "saveResultAsEntity": "cursor0" + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 1 + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "cursor0", + "expectResult": { + "_id": 2 + } + }, + { + "name": "iterateOnce", + "object": "cursor0" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll0", + "filter": {}, + "batchSize": 2 + }, + "commandName": "find", + "databaseName": "database0" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": "long" + }, + "collection": "coll0" + }, + "commandName": "getMore" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/kmsProviders-explicit_kms_credentials.json b/tests/UnifiedSpecTests/valid-pass/kmsProviders-explicit_kms_credentials.json new file mode 100644 index 000000000..7cc74939e --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/kmsProviders-explicit_kms_credentials.json @@ -0,0 +1,52 @@ +{ + "description": "kmsProviders-explicit_kms_credentials", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": "accessKeyId", + "secretAccessKey": "secretAccessKey" + }, + "azure": { + "tenantId": "tenantId", + "clientId": "clientId", + "clientSecret": "clientSecret" + }, + "gcp": { + "email": "email", + "privateKey": "cHJpdmF0ZUtleQo=" + }, + "kmip": { + "endpoint": "endpoint" + }, + "local": { + "key": "a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5a2V5" + } + } + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/kmsProviders-mixed_kms_credential_fields.json b/tests/UnifiedSpecTests/valid-pass/kmsProviders-mixed_kms_credential_fields.json new file mode 100644 index 000000000..363f2a457 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/kmsProviders-mixed_kms_credential_fields.json @@ -0,0 +1,54 @@ +{ + "description": "kmsProviders-mixed_kms_credential_fields", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": "accessKeyId", + "secretAccessKey": { + "$$placeholder": 1 + } + }, + "azure": { + "tenantId": "tenantId", + "clientId": { + "$$placeholder": 1 + }, + "clientSecret": { + "$$placeholder": 1 + } + }, + "gcp": { + "email": "email", + "privateKey": { + "$$placeholder": 1 + } + } + } + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/kmsProviders-placeholder_kms_credentials.json b/tests/UnifiedSpecTests/valid-pass/kmsProviders-placeholder_kms_credentials.json new file mode 100644 index 000000000..3f7721f01 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/kmsProviders-placeholder_kms_credentials.json @@ -0,0 +1,70 @@ +{ + "description": "kmsProviders-placeholder_kms_credentials", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": { + "accessKeyId": { + "$$placeholder": 1 + }, + "secretAccessKey": { + "$$placeholder": 1 + } + }, + "azure": { + "tenantId": { + "$$placeholder": 1 + }, + "clientId": { + "$$placeholder": 1 + }, + "clientSecret": { + "$$placeholder": 1 + } + }, + "gcp": { + "email": { + "$$placeholder": 1 + }, + "privateKey": { + "$$placeholder": 1 + } + }, + "kmip": { + "endpoint": { + "$$placeholder": 1 + } + }, + "local": { + "key": { + "$$placeholder": 1 + } + } + } + } + } + } + ], + "tests": [ + { + "description": "", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/kmsProviders-unconfigured_kms.json b/tests/UnifiedSpecTests/valid-pass/kmsProviders-unconfigured_kms.json new file mode 100644 index 000000000..12ca58094 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/kmsProviders-unconfigured_kms.json @@ -0,0 +1,39 @@ +{ + "description": "kmsProviders-unconfigured_kms", + "schemaVersion": "1.8", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "aws": {}, + "azure": {}, + "gcp": {}, + "kmip": {}, + "local": {} + } + } + } + } + ], + "tests": [ + { + "description": "", + "skipReason": "DRIVERS-2280: waiting on driver support for on-demand credentials", + "operations": [] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/matches-lte-operator.json b/tests/UnifiedSpecTests/valid-pass/matches-lte-operator.json new file mode 100644 index 000000000..4de65c583 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/matches-lte-operator.json @@ -0,0 +1,78 @@ +{ + "description": "matches-lte-operator", + "schemaVersion": "1.9", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0Name" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "initialData": [ + { + "collectionName": "coll0", + "databaseName": "database0Name", + "documents": [] + } + ], + "tests": [ + { + "description": "special lte matching operator", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "y": 1 + } + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll0", + "documents": [ + { + "_id": { + "$$lte": 1 + }, + "y": { + "$$lte": 2 + } + } + ] + }, + "commandName": "insert", + "databaseName": "database0Name" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json b/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json index 4194005eb..50f0d06f0 100644 --- a/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json +++ b/tests/UnifiedSpecTests/valid-pass/poc-change-streams.json @@ -94,6 +94,42 @@ } ], "tests": [ + { + "description": "saveResultAsEntity is optional for createChangeStream", + "runOnRequirements": [ + { + "minServerVersion": "3.8.0", + "topologies": [ + "replicaset" + ] + } + ], + "operations": [ + { + "name": "createChangeStream", + "object": "client0", + "arguments": { + "pipeline": [] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": 1 + }, + "commandName": "aggregate", + "databaseName": "admin" + } + } + ] + } + ] + }, { "description": "Executing a watch helper on a MongoClient results in notifications for changes to all collections in all databases in the cluster.", "runOnRequirements": [ From a35e09e22c5968fcd21396587e8ef30932a8fd4d Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 26 Aug 2022 19:05:31 +0200 Subject: [PATCH 183/321] PHPLIB-912: Skip failing test until test is updated (#960) --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 9caf782dd..f65f3ef5a 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -64,6 +64,8 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/createEntities-operation: createEntities operation' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/entity-cursor-iterateOnce: iterateOnce' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/matches-lte-operator: special lte matching operator' => 'CSOT is not yet implemented (PHPC-1760)', + // Fails on sharded clusters + 'change-streams/change-streams-showExpandedEvents: when showExpandedEvents is true, createIndex events are reported' => 'Fails on sharded clusters (PHPLIB-912)', ]; /** @var UnifiedTestRunner */ From a292d0786a3fd31e3b455624df6da956db23ab46 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 29 Aug 2022 15:38:35 -0400 Subject: [PATCH 184/321] PHPLIB-914: Skip the StaleShardVersion resumability test on 6.1+ Synced with mongodb/specifications@8d897ad01f8c600ddaef139740d5b68fd2950c0e --- .../change-streams/change-streams-resume-errorLabels.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json index c156b550c..f5f4505a9 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json @@ -1478,6 +1478,11 @@ }, { "description": "change stream resumes after StaleShardVersion", + "runOnRequirements": [ + { + "maxServerVersion": "6.0.99" + } + ], "operations": [ { "name": "failPoint", From ca0ce93d651b41472e95fe09a208a25aecfd59ee Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 29 Aug 2022 15:43:36 -0400 Subject: [PATCH 185/321] PHPLIB-924: Tests for updateDescription disambiguatedPaths field on 6.1+ Synced with mongodb/specifications@046db4496e99c79031e51779a4abf4736e25a66b --- .../change-streams-disambiguatedPaths.json | 251 ++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json b/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json new file mode 100644 index 000000000..9a639801e --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json @@ -0,0 +1,251 @@ +{ + "description": "disambiguatedPaths", + "schemaVersion": "1.3", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + } + ], + "runOnRequirements": [ + { + "minServerVersion": "6.1.0", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced", + "sharded" + ] + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [] + } + ], + "tests": [ + { + "description": "disambiguatedPaths is not present when showExpandedEvents is false/unset", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": { + "1": 1 + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "a.1": 2 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "updateDescription": { + "updatedFields": { + "$$exists": true + }, + "removedFields": { + "$$exists": true + }, + "truncatedArrays": { + "$$exists": true + }, + "disambiguatedPaths": { + "$$exists": false + } + } + } + } + ] + }, + { + "description": "disambiguatedPaths is present on updateDescription when an ambiguous path is present", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": { + "1": 1 + } + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "a.1": 2 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "updateDescription": { + "updatedFields": { + "$$exists": true + }, + "removedFields": { + "$$exists": true + }, + "truncatedArrays": { + "$$exists": true + }, + "disambiguatedPaths": { + "a.1": [ + "a", + "1" + ] + } + } + } + } + ] + }, + { + "description": "disambiguatedPaths returns array indices as integers", + "operations": [ + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1, + "a": [ + { + "1": 1 + } + ] + } + } + }, + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [], + "showExpandedEvents": true + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "a.0.1": 2 + } + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "operationType": "update", + "ns": { + "db": "database0", + "coll": "collection0" + }, + "updateDescription": { + "updatedFields": { + "$$exists": true + }, + "removedFields": { + "$$exists": true + }, + "truncatedArrays": { + "$$exists": true + }, + "disambiguatedPaths": { + "a.0.1": [ + "a", + { + "$$type": "int" + }, + "1" + ] + } + } + } + } + ] + } + ] +} From f8eff8dd5b039ea34b1379907d76ca47e5113250 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 29 Aug 2022 15:39:22 -0400 Subject: [PATCH 186/321] PHPLIB-912: showExpandedEvents test fix for spurious mongos failures Reverts previous skip added in a35e09e22c5968fcd21396587e8ef30932a8fd4d Synced with mongodb/specifications@51741620a6af40337b8ec9dcb6fe44f8586f07f6 --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 2 -- .../change-streams-showExpandedEvents.json | 10 +++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index f65f3ef5a..9caf782dd 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -64,8 +64,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/createEntities-operation: createEntities operation' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/entity-cursor-iterateOnce: iterateOnce' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/matches-lte-operator: special lte matching operator' => 'CSOT is not yet implemented (PHPC-1760)', - // Fails on sharded clusters - 'change-streams/change-streams-showExpandedEvents: when showExpandedEvents is true, createIndex events are reported' => 'Fails on sharded clusters (PHPLIB-912)', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json index fe852b544..3eed2f534 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json @@ -275,7 +275,15 @@ "name": "createChangeStream", "object": "collection0", "arguments": { - "pipeline": [], + "pipeline": [ + { + "$match": { + "operationType": { + "$ne": "create" + } + } + } + ], "showExpandedEvents": true }, "saveResultAsEntity": "changeStream0" From a315cc0194f5a7c0e33505d37b47e2cd4c9c1395 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 31 Aug 2022 11:11:30 -0400 Subject: [PATCH 187/321] PHPLIB-942: Fix pattern for matching phpinfo() values (#962) --- tests/FunctionalTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 36992c965..60cf9ff3a 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -290,7 +290,7 @@ public static function getModuleInfo(string $row): ?string phpinfo(INFO_MODULES); $info = ob_get_clean(); - $pattern = sprintf('/^%s([\w ]+)$/m', preg_quote($row . ' => ')); + $pattern = sprintf('/^%s(.*)$/m', preg_quote($row . ' => ')); if (preg_match($pattern, $info, $matches) !== 1) { return null; From 7777e63fca8e561b558a78aac875341126f803f2 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 1 Sep 2022 16:36:03 -0400 Subject: [PATCH 188/321] PHPLIB-944: Document env vars supported by the test suite (#964) --- CONTRIBUTING.md | 71 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 62 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2c035af5e..a37e7f8ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,26 +31,80 @@ $ vendor/bin/simple-phpunit ``` The `phpunit.xml.dist` file is used as the default configuration file for the -test suite. In addition to various PHPUnit options, it defines required -`MONGODB_URI` and `MONGODB_DATABASE` environment variables. You may customize +test suite. In addition to various PHPUnit options, it defines environment +variables such as `MONGODB_URI` and `MONGODB_DATABASE`. You may customize this configuration by creating your own `phpunit.xml` file based on the `phpunit.xml.dist` file we provide. To run the tests in serverless mode, set the `MONGODB_IS_SERVERLESS` environment variable to `on`. To run tests against a cluster that requires authentication, either include the -credentials in the connection string given in the `MONGODB_URI` environment -variable, or set the `MONGODB_USERNAME` and `MONGODB_PASSWORD` environment -variables accordingly. Note that values defined through the environment override -credentials present in the URI. +credentials in the connection string (i.e. `MONGODB_URI`) or set the +`MONGODB_USERNAME` and `MONGODB_PASSWORD` environment variables accordingly. +Note that `MONGODB_USERNAME` and `MONGODB_PASSWORD` will override any +credentials present in the connection string. By default, the `simple-phpunit` binary chooses the correct PHPUnit version for -the PHP version you are running. To run tests against a specific PHPUnit version, -use the `SYMFONY_PHPUNIT_VERSION` environment variable: +the PHP version you are running. To run tests against a specific PHPUnit +version, use the `SYMFONY_PHPUNIT_VERSION` environment variable: ``` $ SYMFONY_PHPUNIT_VERSION=7.5 vendor/bin/simple-phpunit ``` +### Environment Variables + +The test suite references the following environment variables: + + * `MONGODB_DATABASE`: Default database to use in tests. Defaults to + `phplib_test`. + * `MONGODB_PASSWORD`: If specified, this value will be appended as the + `password` URI option for clients constructed by the test suite, which will + override any credentials in the connection string itself. + * `MONGODB_URI`: Connection string. Defaults to `mongodb://127.0.0.1/`, which + assumes a MongoDB server is listening on localhost port 27017. + * `MONGODB_USERNAME`: If specified, this value will be appended as the + `username` URI option for clients constructed by the test suite, which will + override any credentials in the connection string itself. + +The following environment variable is used for [stable API testing](https://github.com/mongodb/specifications/blob/master/source/versioned-api/tests/README.rst): + + * `API_VERSION`: If defined, this value will be used to construct a + [`MongoDB\Driver\ServerApi`](https://www.php.net/manual/en/mongodb-driver-serverapi.construct.php), + which will then be specified as the `serverApi` driver option for clients + created by the test suite. + +The following environment variable is used for [serverless testing](https://github.com/mongodb/specifications/blob/master/source/serverless-testing/README.rst): + + * `MONGODB_IS_SERVERLESS`: Specify a true boolean string + (see: [`FILTER_VALIDATE_BOOLEAN`](https://www.php.net/manual/en/filter.filters.validate.php)) + if `MONGODB_URI` points to a serverless instance. Defaults to false. + +The following environment variables are used for [load balancer testing](https://github.com/mongodb/specifications/blob/master/source/load-balancers/tests/README.rst): + + * `MONGODB_SINGLE_MONGOS_LB_URI`: Connection string to a load balancer backed + by a single mongos host. + * `MONGODB_MULTI_MONGOS_LB_URI`: Connection string to a load balancer backed by + multiple mongos hosts. + +The following environment variables are used for [CSFLE testing](https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst): + + * `AWS_ACCESS_KEY_ID` + * `AWS_SECRET_ACCESS_KEY` + * `AZURE_TENANT_ID` + * `AZURE_CLIENT_ID` + * `AZURE_CLIENT_SECRET` + * `CRYPT_SHARED_LIB_PATH`: If defined, this value will be used to set the + `cryptSharedLibPath` autoEncryption driver option for clients created by the + test suite. + * `GCP_EMAIL` + * `GCP_PRIVATE_KEY` + * `KMIP_ENDPOINT` + * `KMS_ENDPOINT_EXPIRED` + * `KMS_ENDPOINT_WRONG_HOST` + * `KMS_ENDPOINT_REQUIRE_CLIENT_CERT` + * `KMS_TLS_CA_FILE` + * `KMS_TLS_CERTIFICATE_KEY_FILE` + ## Checking coding standards The library's code is checked using [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer), @@ -243,4 +297,3 @@ projects: These tasks can be initiated prior to tagging a new release to ensure that the updated content becomes accessible soon after the release is published. - From 0353b4791087b7edbca9065f064370bc974f8fe1 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Fri, 2 Sep 2022 12:03:26 +0400 Subject: [PATCH 189/321] PHPLIB-932: Use debian11 and include MongoDB 6.0 for load balancer testing (#966) Co-authored-by: levon80999 --- .evergreen/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 044b84c4e..1c47140ce 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -786,8 +786,7 @@ buildvariants: # Load balancer is available from MongoDB 5.0+ - matrix_name: "test-loadBalanced" - # TODO: Add MongoDB 6.0 and use Debian 11 once BUILD-15237 is resolved - matrix_spec: { "os": "debian92", "mongodb-versions": ["5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + matrix_spec: { "os": "debian11", "mongodb-versions": ["5.0", "6.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Load balanced - ${mongodb-versions}" tasks: - name: "test-loadBalanced" From 4bc4607a185db5f52ea3a24dbe36cd25112d00e8 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Fri, 2 Sep 2022 12:05:46 +0400 Subject: [PATCH 190/321] PHPLIB-918: Add test that reads are not retried in a transaction (#963) Co-authored-by: levon80999 --- .../do-not-retry-read-in-transaction.json | 115 ++++++++++ .../retryable-abort-handshake.json | 204 +++++++++++++++++ .../retryable-commit-handshake.json | 211 ++++++++++++++++++ 3 files changed, 530 insertions(+) create mode 100644 tests/UnifiedSpecTests/transactions/do-not-retry-read-in-transaction.json create mode 100644 tests/UnifiedSpecTests/transactions/retryable-abort-handshake.json create mode 100644 tests/UnifiedSpecTests/transactions/retryable-commit-handshake.json diff --git a/tests/UnifiedSpecTests/transactions/do-not-retry-read-in-transaction.json b/tests/UnifiedSpecTests/transactions/do-not-retry-read-in-transaction.json new file mode 100644 index 000000000..6d9dc704b --- /dev/null +++ b/tests/UnifiedSpecTests/transactions/do-not-retry-read-in-transaction.json @@ -0,0 +1,115 @@ +{ + "description": "do not retry read in a transaction", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "topologies": [ + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "topologies": [ + "sharded", + "load-balanced" + ] + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent" + ], + "uriOptions": { + "retryReads": true + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "retryable-read-in-transaction-test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + } + ], + "tests": [ + { + "description": "find does not retry in a transaction", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "find" + ], + "closeConnection": true + } + } + } + }, + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": {}, + "session": "session0" + }, + "expectError": { + "isError": true, + "errorLabelsContain": [ + "TransientTransactionError" + ] + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "coll", + "filter": {}, + "startTransaction": true + }, + "commandName": "find", + "databaseName": "retryable-read-in-transaction-test" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/transactions/retryable-abort-handshake.json b/tests/UnifiedSpecTests/transactions/retryable-abort-handshake.json new file mode 100644 index 000000000..4ad56e2f2 --- /dev/null +++ b/tests/UnifiedSpecTests/transactions/retryable-abort-handshake.json @@ -0,0 +1,204 @@ +{ + "description": "retryable abortTransaction on handshake errors", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ], + "serverless": "forbid", + "auth": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent", + "connectionCheckOutStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "retryable-handshake-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + }, + { + "session": { + "id": "session1", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "coll", + "databaseName": "retryable-handshake-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "AbortTransaction succeeds after handshake network error", + "skipReason": "DRIVERS-2032: Pinned servers need to be checked if they are still selectable", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 2, + "x": 22 + } + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "session": "session1", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "saslContinue", + "ping" + ], + "closeConnection": true + } + } + } + }, + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1 + }, + "session": "session1" + }, + "expectError": { + "isError": true + } + }, + { + "name": "abortTransaction", + "object": "session0" + } + ], + "expectEvents": [ + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + } + ] + }, + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "startTransaction": true + }, + "commandName": "insert", + "databaseName": "retryable-handshake-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "ping": 1 + }, + "databaseName": "retryable-handshake-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "abortTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + } + }, + "commandName": "abortTransaction", + "databaseName": "admin" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll", + "databaseName": "retryable-handshake-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/transactions/retryable-commit-handshake.json b/tests/UnifiedSpecTests/transactions/retryable-commit-handshake.json new file mode 100644 index 000000000..d9315a8fc --- /dev/null +++ b/tests/UnifiedSpecTests/transactions/retryable-commit-handshake.json @@ -0,0 +1,211 @@ +{ + "description": "retryable commitTransaction on handshake errors", + "schemaVersion": "1.4", + "runOnRequirements": [ + { + "minServerVersion": "4.2", + "topologies": [ + "replicaset", + "sharded", + "load-balanced" + ], + "serverless": "forbid", + "auth": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false, + "observeEvents": [ + "commandStartedEvent", + "connectionCheckOutStartedEvent" + ], + "uriOptions": { + "retryWrites": false + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "retryable-handshake-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll" + } + }, + { + "session": { + "id": "session0", + "client": "client0" + } + }, + { + "session": { + "id": "session1", + "client": "client0" + } + } + ], + "initialData": [ + { + "collectionName": "coll", + "databaseName": "retryable-handshake-tests", + "documents": [ + { + "_id": 1, + "x": 11 + } + ] + } + ], + "tests": [ + { + "description": "CommitTransaction succeeds after handshake network error", + "skipReason": "DRIVERS-2032: Pinned servers need to be checked if they are still selectable", + "operations": [ + { + "name": "startTransaction", + "object": "session0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "session": "session0", + "document": { + "_id": 2, + "x": 22 + } + } + }, + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "session": "session1", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 2 + }, + "data": { + "failCommands": [ + "saslContinue", + "ping" + ], + "closeConnection": true + } + } + } + }, + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "ping", + "command": { + "ping": 1 + }, + "session": "session1" + }, + "expectError": { + "isError": true + } + }, + { + "name": "commitTransaction", + "object": "session0" + } + ], + "expectEvents": [ + { + "client": "client0", + "eventType": "cmap", + "events": [ + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + }, + { + "connectionCheckOutStartedEvent": {} + } + ] + }, + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "insert": "coll", + "documents": [ + { + "_id": 2, + "x": 22 + } + ], + "startTransaction": true + }, + "commandName": "insert", + "databaseName": "retryable-handshake-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "ping": 1 + }, + "databaseName": "retryable-handshake-tests" + } + }, + { + "commandStartedEvent": { + "command": { + "commitTransaction": 1, + "lsid": { + "$$sessionLsid": "session0" + } + }, + "commandName": "commitTransaction", + "databaseName": "admin" + } + } + ] + } + ], + "outcome": [ + { + "collectionName": "coll", + "databaseName": "retryable-handshake-tests", + "documents": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ] + } + ] + } + ] +} From 86da93b8100d4820cf884ad73f662552ca5e34f4 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Fri, 2 Sep 2022 19:02:32 +0400 Subject: [PATCH 191/321] PHPLIB-930: Update expected error in fle2-InsertFind-Unindexed test (#967) --- .../client-side-encryption/tests/fle2-InsertFind-Unindexed.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json index 1a7509590..c1bdc9076 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json @@ -241,7 +241,7 @@ } }, "result": { - "errorContains": "Cannot query" + "errorContains": "encrypt" } } ] From 6ca038415ca5ec28037a93e6880f7d49be423463 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 6 Sep 2022 14:12:46 -0400 Subject: [PATCH 192/321] Fix typo in fullDocument option docs (#969) This typo originated in 2704fb05e3a96cc63544c2f6e0c33008740b6915 for PHPLIB-814 --- docs/includes/apiargs-method-watch-option.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/includes/apiargs-method-watch-option.yaml b/docs/includes/apiargs-method-watch-option.yaml index 01b7f7659..1aa1de2b2 100644 --- a/docs/includes/apiargs-method-watch-option.yaml +++ b/docs/includes/apiargs-method-watch-option.yaml @@ -17,9 +17,9 @@ description: | operations. By default, change streams only return the delta of fields (via an - "udateDescription" field) for update operations and "fullDocument" is omitted. - Insert and replace operations always include the "fullDocument" field. Delete - operations omit the field as the document no longer exists. + "updateDescription" field) for update operations and "fullDocument" is + omitted. Insert and replace operations always include the "fullDocument" + field. Delete operations omit the field as the document no longer exists. Specify "updateLookup" to return the current majority-committed version of the updated document. From 0fe1a0f0b9ee54ce270980b2651b94fcc58921ff Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 7 Sep 2022 20:53:58 -0400 Subject: [PATCH 193/321] PHPLIB-911: Test with consistent version of crypt_shared (#965) Use the crypt_shared library provisioned by download-mongodb.sh and add an additional task to disable the library and fall back to mongocryptd. This also revises how we pass environment variables into run-tests.sh and the test suite, and restructures run-tests.sh a bit. --- .evergreen/config.yml | 49 ++++++++++++++++++++++------------------- .evergreen/run-tests.sh | 43 ++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 69333d384..cd21e97c7 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -176,7 +176,7 @@ functions: script: | ${PREPARE_SHELL} MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} LOAD_BALANCER=${LOAD_BALANCER} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh - # run-orchestration generates expansion file with the MONGODB_URI for the cluster + # run-orchestration generates expansion file with MONGODB_URI and CRYPT_SHARED_LIB_PATH - command: expansions.update params: file: mo-expansion.yml @@ -246,9 +246,16 @@ functions: export KMS_ENDPOINT_REQUIRE_CLIENT_CERT="${client_side_encryption_kms_endpoint_require_client_cert}" export KMS_TLS_CA_FILE="${client_side_encryption_kms_tls_ca_file}" export KMS_TLS_CERTIFICATE_KEY_FILE="${client_side_encryption_kms_tls_certificate_key_file}" - export CRYPT_SHARED_LIB_PATH="${client_side_encryption_crypt_shared_lib_path}" export PATH="${PHP_PATH}/bin:$PATH" - API_VERSION=${API_VERSION} PHP_VERSION=${PHP_VERSION} TESTS=${TESTS} AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + + API_VERSION=${API_VERSION} \ + CRYPT_SHARED_LIB_PATH=${CRYPT_SHARED_LIB_PATH} \ + MONGODB_URI="${MONGODB_URI}" \ + PHP_VERSION=${PHP_VERSION} \ + SKIP_CRYPT_SHARED=${SKIP_CRYPT_SHARED} \ + SSL=${SSL} \ + TESTS=${TESTS} \ + sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run atlas data lake test": - command: shell.exec @@ -258,7 +265,10 @@ functions: script: | ${PREPARE_SHELL} export PATH="${PHP_PATH}/bin:$PATH" - PHP_VERSION=${PHP_VERSION} TESTS="atlas-data-lake" AUTH=${AUTH} SSL=${SSL} MONGODB_URI="${MONGODB_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + + MONGODB_URI="mongodb://mhuser:pencil@127.0.0.1:27017" \ + TESTS="atlas-data-lake" \ + sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "run serverless tests": - command: shell.exec @@ -271,7 +281,12 @@ functions: export MONGODB_USERNAME=${SERVERLESS_ATLAS_USER} export MONGODB_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} export PATH="${PHP_PATH}/bin:$PATH" - PHP_VERSION=${PHP_VERSION} TESTS="serverless" MONGODB_URI="${SERVERLESS_URI}" sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh + + CRYPT_SHARED_LIB_PATH=${CRYPT_SHARED_LIB_PATH} \ + MONGODB_URI="${SERVERLESS_URI}" \ + SKIP_CRYPT_SHARED=${SKIP_CRYPT_SHARED} \ + TESTS="serverless" \ + sh ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh "cleanup": - command: shell.exec @@ -378,18 +393,6 @@ functions: - key: client_side_encryption_kmip_endpoint value: localhost:5698 - "fetch crypt_shared": - - command: shell.exec - params: - script: | - # TODO: Specify same version provisioned by download-mongodb.sh (see: DRIVERS-2355) - python3 ${DRIVERS_TOOLS}/.evergreen/mongodl.py --component crypt_shared --version latest --only "**/mongo_crypt_v1.so" --out ${DRIVERS_TOOLS}/.evergreen/csfle --strip-path-components 1 - - command: expansions.update - params: - updates: - - key: client_side_encryption_crypt_shared_lib_path - value: ${DRIVERS_TOOLS}/.evergreen/csfle/mongo_crypt_v1.so - pre: - func: "fetch source" - func: "prepare resources" @@ -521,15 +524,15 @@ tasks: SSL: "yes" # Note: "stop load balancer" will be called from "post" - - name: "test-crypt_shared" + - name: "test-skip_crypt_shared" commands: - func: "bootstrap mongo-orchestration" vars: TOPOLOGY: "replica_set" - func: "start kms servers" - - func: "fetch crypt_shared" - func: "run tests" vars: + SKIP_CRYPT_SHARED: "yes" TESTS: "csfle" # }}} @@ -792,9 +795,9 @@ buildvariants: tasks: - name: "test-loadBalanced" -# CSFLE crypt_shared is available from MongoDB 6.0+ -- matrix_name: "test-csfle-crypt_shared" +# CSFLE crypt_shared is available from MongoDB 6.0+, so explicitly test without it to allow use of mongocryptd +- matrix_name: "test-csfle-skip_crypt_shared" matrix_spec: { "os": "debian11", "mongodb-versions": "6.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } - display_name: "CSFLE crypt_shared - ${mongodb-versions}" + display_name: "CSFLE skip_crypt_shared - ${mongodb-versions}" tasks: - - name: "test-crypt_shared" + - name: "test-skip_crypt_shared" diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 9cc49ff0c..3bc0f9601 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -1,16 +1,16 @@ #!/bin/sh set -o errexit # Exit the script with error if any of the commands fail -# Supported/used environment variables: -# SSL Set to "yes" to enable SSL. Defaults to "nossl" -# MONGODB_URI Set the suggested connection MONGODB_URI (including credentials and topology info) -# API_VERSION Optional API_VERSION environment variable for run-tests.php -# IS_MATRIX_TESTING Set to "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked. - -SSL=${SSL:-nossl} -MONGODB_URI=${MONGODB_URI:-} -API_VERSION=${API_VERSION:-} -IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} +# Supported environment variables +API_VERSION=${API_VERSION:-} # Optional API_VERSION environment variable +CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH:-}" # Optional path to crypt_shared library +DRIVER_MONGODB_VERSION={$DRIVER_MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true" +IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} # Specify "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked. +MONGODB_URI=${MONGODB_URI:-} # Connection string (including credentials and topology info) +MONGODB_VERSION=${MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true" +SKIP_CRYPT_SHARED="${SKIP_CRYPT_SHARED:-no}" # Specify "yes" to ignore CRYPT_SHARED_LIB_PATH. Defaults to "no" +SSL=${SSL:-no} # Specify "yes" to enable SSL. Defaults to "no" +TESTS=${TESTS:-} # Optional test group. Defaults to all tests # For matrix testing, we have to determine the correct driver version if [ "${IS_MATRIX_TESTING}" = "true" ]; then @@ -42,7 +42,7 @@ if [ "${IS_MATRIX_TESTING}" = "true" ]; then fi # Enable verbose output to see skipped and incomplete tests -PHPUNIT_OPTS="${PHPUNIT_OPTS} -v" +PHPUNIT_OPTS="${PHPUNIT_OPTS} -v --configuration phpunit.evergreen.xml" # Determine if MONGODB_URI already has a query string SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat) @@ -57,29 +57,34 @@ fi echo "Running tests with URI: $MONGODB_URI" -# Disable failing PHPUnit due to deprecations +# Disable PHPUnit test failures due to deprecations +# See: https://symfony.com/doc/current/components/phpunit_bridge.html#internal-deprecations export SYMFONY_DEPRECATIONS_HELPER=999999 -# Run the tests, and store the results in a Evergreen compatible JSON results file +# Export environment vars that may be referenced by the test suite +export API_VERSION="${API_VERSION}" +export CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH}" +export MONGODB_URI="${MONGODB_URI}" + +# Run the tests, and store the results in a junit result file case "$TESTS" in atlas-data-lake*) - MONGODB_URI="mongodb://mhuser:pencil@127.0.0.1:27017" - php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --testsuite "Atlas Data Lake Test Suite" $PHPUNIT_OPTS + php vendor/bin/simple-phpunit $PHPUNIT_OPTS --testsuite "Atlas Data Lake Test Suite" ;; csfle) - php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group csfle $PHPUNIT_OPTS + php vendor/bin/simple-phpunit $PHPUNIT_OPTS --group csfle ;; versioned-api) - php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group versioned-api $PHPUNIT_OPTS + php vendor/bin/simple-phpunit $PHPUNIT_OPTS --group versioned-api ;; serverless) - php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml --group serverless $PHPUNIT_OPTS + php vendor/bin/simple-phpunit $PHPUNIT_OPTS --group serverless ;; *) - php vendor/bin/simple-phpunit --configuration phpunit.evergreen.xml $PHPUNIT_OPTS + php vendor/bin/simple-phpunit $PHPUNIT_OPTS ;; esac From 0b8555705d2f9c12ab2e5cebee6b594cdfe6b4e0 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 7 Sep 2022 23:32:09 -0400 Subject: [PATCH 194/321] Fix access of $DRIVER_MONGODB_VERSION env var (#970) This corrects a typo introduced in 0fe1a0f0b9ee54ce270980b2651b94fcc58921ff --- .evergreen/run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 3bc0f9601..c56e86b66 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -4,7 +4,7 @@ set -o errexit # Exit the script with error if any of the commands fail # Supported environment variables API_VERSION=${API_VERSION:-} # Optional API_VERSION environment variable CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH:-}" # Optional path to crypt_shared library -DRIVER_MONGODB_VERSION={$DRIVER_MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true" +DRIVER_MONGODB_VERSION=${DRIVER_MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true" IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} # Specify "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked. MONGODB_URI=${MONGODB_URI:-} # Connection string (including credentials and topology info) MONGODB_VERSION=${MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true" From c7f05a0c785e27286693f01f41f80f34f5870e1a Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Thu, 8 Sep 2022 15:40:46 +0400 Subject: [PATCH 195/321] PHPLIB-678: Remove obsolete handling of options arg for insertMany (#968) --- tests/UnifiedSpecTests/Operation.php | 6 +----- tests/UnifiedSpecTests/Util.php | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php index ca13f32e5..54f634b02 100644 --- a/tests/UnifiedSpecTests/Operation.php +++ b/tests/UnifiedSpecTests/Operation.php @@ -507,16 +507,12 @@ static function ($request) { ); case 'insertMany': - // Merge nested and top-level options (see: SPEC-1158) - $options = isset($args['options']) ? (array) $args['options'] : []; - $options += array_diff_key($args, ['documents' => 1]); - assertArrayHasKey('documents', $args); assertIsArray($args['documents']); return $collection->insertMany( $args['documents'], - $options + array_diff_key($args, ['documents' => 1]) ); case 'insertOne': diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 1572e16d4..1c0c249e7 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -104,7 +104,7 @@ final class Util 'findOneAndUpdate' => ['let', 'returnDocument', 'filter', 'update', 'session', 'upsert', 'projection', 'remove', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'maxTimeMS', 'sort', 'comment'], 'updateMany' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], 'updateOne' => ['let', 'filter', 'update', 'session', 'upsert', 'arrayFilters', 'bypassDocumentValidation', 'collation', 'hint', 'comment'], - 'insertMany' => ['options', 'documents', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], + 'insertMany' => ['documents', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], 'insertOne' => ['document', 'session', 'bypassDocumentValidation', 'comment'], 'listIndexes' => ['session', 'maxTimeMS', 'comment'], 'mapReduce' => ['map', 'reduce', 'out', 'session', 'bypassDocumentValidation', 'collation', 'finalize', 'jsMode', 'limit', 'maxTimeMS', 'query', 'scope', 'sort', 'verbose', 'comment'], From 1e20e8d4e44eddd8e4e23758a292ffdc6aa946d6 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 9 Sep 2022 19:33:30 -0400 Subject: [PATCH 196/321] Update Composer install template --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a37e7f8ca..80fabae48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -257,7 +257,7 @@ https://mongodb.com/docs/php-library/current/ This library may be installed or upgraded with: - composer require mongodb/mongodb^X.Y.Z + composer require mongodb/mongodb:X.Y.Z Installation instructions for the `mongodb` extension may be found in the [PHP.net documentation](https://php.net/manual/en/mongodb.installation.php). ``` From 1b29a6d71e5511ea46b596461442ca94069bdf42 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 13 Sep 2022 14:41:33 +0200 Subject: [PATCH 197/321] PHPLIB-599: Typing improvements (#959) * PHPLIB-600: Add type definitions for parameters * PHPLIB-602: Add return type definitions where applicable * Enable object type for parameters * Add comment about using declare * Remove useless param and return annotations * Remove redundant type casts * Add return types to internal classes * Use object consistently in GridFS classes * Remove useless type annotations * Remove unnecessary cast --- phpcs.xml.dist | 16 +--- src/BulkWriteResult.php | 10 +-- src/ChangeStream.php | 15 +--- src/Client.php | 13 ++-- src/Collection.php | 21 +++-- src/Command/ListCollections.php | 15 ++-- src/Command/ListDatabases.php | 10 +-- src/Database.php | 27 +++---- src/Exception/BadMethodCallException.php | 4 +- src/Exception/InvalidArgumentException.php | 2 +- src/GridFS/Bucket.php | 37 ++++----- src/GridFS/CollectionWrapper.php | 78 ++++++------------- src/GridFS/Exception/CorruptFileException.php | 6 +- .../Exception/FileNotFoundException.php | 4 +- src/GridFS/ReadableStream.php | 49 ++++-------- src/GridFS/StreamWrapper.php | 48 +++++------- src/GridFS/WritableStream.php | 30 +++---- src/InsertManyResult.php | 8 +- src/InsertOneResult.php | 3 +- src/MapReduceResult.php | 2 +- src/Model/BSONArray.php | 1 - src/Model/BSONDocument.php | 6 +- src/Model/BSONIterator.php | 7 +- src/Model/CachingIterator.php | 20 ++--- src/Model/CallbackIterator.php | 12 +-- src/Model/ChangeStreamIterator.php | 24 ++---- src/Model/CollectionInfo.php | 4 - src/Model/CollectionInfoCommandIterator.php | 10 +-- src/Model/DatabaseInfoLegacyIterator.php | 24 ++---- src/Model/IndexInfoIteratorIterator.php | 10 +-- src/Model/IndexInput.php | 9 +-- src/Operation/Aggregate.php | 12 +-- src/Operation/BulkWrite.php | 13 ++-- src/Operation/Count.php | 15 ++-- src/Operation/CountDocuments.php | 12 +-- src/Operation/CreateCollection.php | 14 ++-- src/Operation/CreateIndexes.php | 13 ++-- src/Operation/DatabaseCommand.php | 8 +- src/Operation/Delete.php | 15 ++-- src/Operation/DeleteMany.php | 4 +- src/Operation/DeleteOne.php | 4 +- src/Operation/Distinct.php | 19 ++--- src/Operation/DropCollection.php | 14 ++-- src/Operation/DropDatabase.php | 12 +-- src/Operation/DropIndexes.php | 16 ++-- src/Operation/EstimatedDocumentCount.php | 8 +- src/Operation/Executable.php | 1 - src/Operation/Explain.php | 11 +-- src/Operation/Explainable.php | 1 - src/Operation/Find.php | 15 ++-- src/Operation/FindAndModify.php | 15 ++-- src/Operation/FindOne.php | 4 +- src/Operation/FindOneAndDelete.php | 4 +- src/Operation/FindOneAndReplace.php | 4 +- src/Operation/FindOneAndUpdate.php | 4 +- src/Operation/InsertMany.php | 13 ++-- src/Operation/InsertOne.php | 13 ++-- src/Operation/ListCollectionNames.php | 3 +- src/Operation/ListCollections.php | 5 +- src/Operation/ListDatabaseNames.php | 2 - src/Operation/ListDatabases.php | 1 - src/Operation/ListIndexes.php | 14 ++-- src/Operation/MapReduce.php | 23 ++---- src/Operation/ModifyCollection.php | 10 +-- src/Operation/RenameCollection.php | 8 +- src/Operation/ReplaceOne.php | 3 +- src/Operation/Update.php | 18 ++--- src/Operation/UpdateMany.php | 4 +- src/Operation/UpdateOne.php | 4 +- src/Operation/Watch.php | 29 ++----- src/Operation/WithTransaction.php | 6 +- src/functions.php | 19 +---- tests/ClientFunctionalTest.php | 3 - tests/Collection/CollectionFunctionalTest.php | 16 ++-- tests/Collection/CrudSpecFunctionalTest.php | 23 +----- tests/Database/DatabaseFunctionalTest.php | 9 ++- tests/DocumentationExamplesTest.php | 2 - tests/FunctionalTestCase.php | 8 -- tests/GridFS/BucketFunctionalTest.php | 9 --- tests/GridFS/FunctionalTestCase.php | 2 - tests/Model/ChangeStreamIteratorTest.php | 15 ++-- tests/Operation/AggregateFunctionalTest.php | 3 - tests/Operation/BulkWriteFunctionalTest.php | 2 - .../Operation/CreateIndexesFunctionalTest.php | 3 - tests/Operation/DeleteFunctionalTest.php | 2 - tests/Operation/DeleteTest.php | 19 ++++- .../Operation/DropDatabaseFunctionalTest.php | 3 - tests/Operation/DropIndexesFunctionalTest.php | 2 - tests/Operation/ExplainFunctionalTest.php | 2 - .../Operation/FindAndModifyFunctionalTest.php | 2 - tests/Operation/FindFunctionalTest.php | 3 - tests/Operation/FindOneFunctionalTest.php | 2 - tests/Operation/MapReduceFunctionalTest.php | 2 - tests/Operation/UpdateFunctionalTest.php | 2 - tests/PHPUnit/Functions.php | 14 +--- tests/SpecTests/CommandExpectations.php | 3 - tests/SpecTests/Context.php | 2 - tests/SpecTests/DocumentsMatchConstraint.php | 10 +-- tests/SpecTests/FunctionalTestCase.php | 18 ----- tests/SpecTests/Operation.php | 26 +------ tests/SpecTests/ResultExpectation.php | 5 -- tests/SpecTests/TransactionsSpecTest.php | 1 - tests/TestCase.php | 50 ++---------- tests/UnifiedSpecTests/Context.php | 2 - tests/UnifiedSpecTests/EventCollector.php | 3 +- 105 files changed, 351 insertions(+), 855 deletions(-) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 42a382a7b..639bfcdf5 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -105,8 +105,6 @@ - - @@ -114,7 +112,6 @@ - @@ -128,13 +125,10 @@ - - - @@ -144,7 +138,6 @@ - @@ -162,12 +155,9 @@ - - - - - src - + + + src diff --git a/src/BulkWriteResult.php b/src/BulkWriteResult.php index 1a1f3ed41..731c49294 100644 --- a/src/BulkWriteResult.php +++ b/src/BulkWriteResult.php @@ -28,16 +28,12 @@ class BulkWriteResult /** @var WriteResult */ private $writeResult; - /** @var mixed[] */ + /** @var array */ private $insertedIds; /** @var boolean */ private $isAcknowledged; - /** - * @param WriteResult $writeResult - * @param mixed[] $insertedIds - */ public function __construct(WriteResult $writeResult, array $insertedIds) { $this->writeResult = $writeResult; @@ -90,7 +86,7 @@ public function getInsertedCount() * field value. Any driver-generated ID will be a MongoDB\BSON\ObjectId * instance. * - * @return mixed[] + * @return array */ public function getInsertedIds() { @@ -165,7 +161,7 @@ public function getUpsertedCount() * This method should only be called if the write was acknowledged. * * @see BulkWriteResult::isAcknowledged() - * @return mixed[] + * @return array * @throws BadMethodCallException is the write result is unacknowledged */ public function getUpsertedIds() diff --git a/src/ChangeStream.php b/src/ChangeStream.php index 551024198..cfd10e6f4 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -90,8 +90,6 @@ class ChangeStream implements Iterator /** * @internal - * @param ChangeStreamIterator $iterator - * @param callable $resumeCallable */ public function __construct(ChangeStreamIterator $iterator, callable $resumeCallable) { @@ -194,10 +192,8 @@ public function valid() * Determines if an exception is a resumable error. * * @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#resumable-error - * @param RuntimeException $exception - * @return boolean */ - private function isResumableError(RuntimeException $exception) + private function isResumableError(RuntimeException $exception): bool { if ($exception instanceof ConnectionException) { return true; @@ -224,7 +220,7 @@ private function isResumableError(RuntimeException $exception) * @param boolean $incrementKey Increment $key if there is a current result * @throws ResumeTokenException */ - private function onIteration($incrementKey) + private function onIteration(bool $incrementKey): void { /* If the cursorId is 0, the server has invalidated the cursor and we * will never perform another getMore nor need to resume since any @@ -251,10 +247,8 @@ private function onIteration($incrementKey) /** * Recreates the ChangeStreamIterator after a resumable server error. - * - * @return void */ - private function resume() + private function resume(): void { $this->iterator = call_user_func($this->resumeCallable, $this->getResumeToken(), $this->hasAdvanced); $this->iterator->rewind(); @@ -265,10 +259,9 @@ private function resume() /** * Either resumes after a resumable error or re-throws the exception. * - * @param RuntimeException $exception * @throws RuntimeException */ - private function resumeOrThrow(RuntimeException $exception) + private function resumeOrThrow(RuntimeException $exception): void { if ($this->isResumableError($exception)) { $this->resume(); diff --git a/src/Client.php b/src/Client.php index 181ac733c..7f15ba12b 100644 --- a/src/Client.php +++ b/src/Client.php @@ -98,7 +98,7 @@ class Client * @throws DriverInvalidArgumentException for parameter/option parsing errors in the driver * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = []) + public function __construct(string $uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = []) { $driverOptions += ['typeMap' => self::$defaultTypeMap]; @@ -116,7 +116,7 @@ public function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [ $driverOptions['driver'] = $this->mergeDriverInfo($driverOptions['driver'] ?? []); - $this->uri = (string) $uri; + $this->uri = $uri; $this->typeMap = $driverOptions['typeMap'] ?? null; unset($driverOptions['typeMap']); @@ -155,7 +155,7 @@ public function __debugInfo() * @param string $databaseName Name of the database to select * @return Database */ - public function __get($databaseName) + public function __get(string $databaseName) { return $this->selectDatabase($databaseName); } @@ -201,7 +201,7 @@ public function createClientEncryption(array $options) * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function dropDatabase($databaseName, array $options = []) + public function dropDatabase(string $databaseName, array $options = []) { if (! isset($options['typeMap'])) { $options['typeMap'] = $this->typeMap; @@ -290,7 +290,6 @@ public function listDatabaseNames(array $options = []): Iterator * List databases. * * @see ListDatabases::__construct() for supported options - * @param array $options * @return DatabaseInfoIterator * @throws UnexpectedValueException if the command response was malformed * @throws InvalidArgumentException for parameter/option parsing errors @@ -314,7 +313,7 @@ public function listDatabases(array $options = []) * @return Collection * @throws InvalidArgumentException for parameter/option parsing errors */ - public function selectCollection($databaseName, $collectionName, array $options = []) + public function selectCollection(string $databaseName, string $collectionName, array $options = []) { $options += ['typeMap' => $this->typeMap]; @@ -330,7 +329,7 @@ public function selectCollection($databaseName, $collectionName, array $options * @return Database * @throws InvalidArgumentException for parameter/option parsing errors */ - public function selectDatabase($databaseName, array $options = []) + public function selectDatabase(string $databaseName, array $options = []) { $options += ['typeMap' => $this->typeMap]; diff --git a/src/Collection.php b/src/Collection.php index bc864256c..517cd307a 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -126,13 +126,13 @@ class Collection * @param array $options Collection options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct(Manager $manager, $databaseName, $collectionName, array $options = []) + public function __construct(Manager $manager, string $databaseName, string $collectionName, array $options = []) { - if (strlen((string) $databaseName) < 1) { + if (strlen($databaseName) < 1) { throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); } - if (strlen((string) $collectionName) < 1) { + if (strlen($collectionName) < 1) { throw new InvalidArgumentException('$collectionName is invalid: ' . $collectionName); } @@ -153,8 +153,8 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } $this->manager = $manager; - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern(); $this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference(); $this->typeMap = $options['typeMap'] ?? self::$defaultTypeMap; @@ -446,13 +446,13 @@ public function deleteOne($filter, array $options = []) * @param string $fieldName Field for which to return distinct values * @param array|object $filter Query by which to filter documents * @param array $options Command options - * @return mixed[] + * @return array * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if options are not supported by the selected server * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function distinct($fieldName, $filter = [], array $options = []) + public function distinct(string $fieldName, $filter = [], array $options = []) { if (! isset($options['readPreference']) && ! is_in_transaction($options)) { $options['readPreference'] = $this->readPreference; @@ -938,7 +938,6 @@ public function insertOne($document, array $options = []) * Returns information for all indexes for the collection. * * @see ListIndexes::__construct() for supported options - * @param array $options * @return IndexInfoIterator * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -1007,9 +1006,9 @@ public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, * Renames the collection. * * @see RenameCollection::__construct() for supported options - * @param string $toCollectionName New name of the collection - * @param ?string $toDatabaseName New database name of the collection. Defaults to the original database. - * @param array $options Additional options + * @param string $toCollectionName New name of the collection + * @param string|null $toDatabaseName New database name of the collection. Defaults to the original database. + * @param array $options Additional options * @return array|object Command result document * @throws UnsupportedException if options are not supported by the selected server * @throws InvalidArgumentException for parameter/option parsing errors diff --git a/src/Command/ListCollections.php b/src/Command/ListCollections.php index 8a017558f..a970aeb07 100644 --- a/src/Command/ListCollections.php +++ b/src/Command/ListCollections.php @@ -73,7 +73,7 @@ class ListCollections implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, array $options = []) + public function __construct(string $databaseName, array $options = []) { if (isset($options['authorizedCollections']) && ! is_bool($options['authorizedCollections'])) { throw InvalidArgumentException::invalidType('"authorizedCollections" option', $options['authorizedCollections'], 'boolean'); @@ -95,7 +95,7 @@ public function __construct($databaseName, array $options = []) throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); } - $this->databaseName = (string) $databaseName; + $this->databaseName = $databaseName; $this->options = $options; } @@ -103,11 +103,9 @@ public function __construct($databaseName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server - * @return CachingIterator * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function execute(Server $server) + public function execute(Server $server): CachingIterator { $cursor = $server->executeReadCommand($this->databaseName, $this->createCommand(), $this->createOptions()); $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); @@ -117,10 +115,8 @@ public function execute(Server $server) /** * Create the listCollections command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = ['listCollections' => 1]; @@ -144,9 +140,8 @@ private function createCommand() * the command be executed on the primary. * * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Command/ListDatabases.php b/src/Command/ListDatabases.php index 3d75fa96c..4dabc6ed2 100644 --- a/src/Command/ListDatabases.php +++ b/src/Command/ListDatabases.php @@ -99,12 +99,11 @@ public function __construct(array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array An array of database info structures * @throws UnexpectedValueException if the command response was malformed * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function execute(Server $server) + public function execute(Server $server): array { $cursor = $server->executeReadCommand('admin', $this->createCommand(), $this->createOptions()); $cursor->setTypeMap(['root' => 'array', 'document' => 'array']); @@ -119,10 +118,8 @@ public function execute(Server $server) /** * Create the listDatabases command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = ['listDatabases' => 1]; @@ -146,9 +143,8 @@ private function createCommand() * the command be executed on the primary. * * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Database.php b/src/Database.php index 4d8a74463..9bb2484dd 100644 --- a/src/Database.php +++ b/src/Database.php @@ -104,9 +104,9 @@ class Database * @param array $options Database options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct(Manager $manager, $databaseName, array $options = []) + public function __construct(Manager $manager, string $databaseName, array $options = []) { - if (strlen((string) $databaseName) < 1) { + if (strlen($databaseName) < 1) { throw new InvalidArgumentException('$databaseName is invalid: ' . $databaseName); } @@ -127,7 +127,7 @@ public function __construct(Manager $manager, $databaseName, array $options = [] } $this->manager = $manager; - $this->databaseName = (string) $databaseName; + $this->databaseName = $databaseName; $this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern(); $this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference(); $this->typeMap = $options['typeMap'] ?? self::$defaultTypeMap; @@ -164,7 +164,7 @@ public function __debugInfo() * @param string $collectionName Name of the collection to select * @return Collection */ - public function __get($collectionName) + public function __get(string $collectionName) { return $this->selectCollection($collectionName); } @@ -257,14 +257,12 @@ public function command($command, array $options = []) * Create a new collection explicitly. * * @see CreateCollection::__construct() for supported options - * @param string $collectionName - * @param array $options * @return array|object Command result document * @throws UnsupportedException if options are not supported by the selected server * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function createCollection($collectionName, array $options = []) + public function createCollection(string $collectionName, array $options = []) { if (! isset($options['typeMap'])) { $options['typeMap'] = $this->typeMap; @@ -340,7 +338,7 @@ public function drop(array $options = []) * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function dropCollection($collectionName, array $options = []) + public function dropCollection(string $collectionName, array $options = []) { if (! isset($options['typeMap'])) { $options['typeMap'] = $this->typeMap; @@ -453,7 +451,6 @@ public function listCollectionNames(array $options = []): Iterator * Returns information for all collections in this database. * * @see ListCollections::__construct() for supported options - * @param array $options * @return CollectionInfoIterator * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -477,7 +474,7 @@ public function listCollections(array $options = []) * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function modifyCollection($collectionName, array $collectionOptions, array $options = []) + public function modifyCollection(string $collectionName, array $collectionOptions, array $options = []) { if (! isset($options['typeMap'])) { $options['typeMap'] = $this->typeMap; @@ -498,10 +495,10 @@ public function modifyCollection($collectionName, array $collectionOptions, arra * Rename a collection within this database. * * @see RenameCollection::__construct() for supported options - * @param string $fromCollectionName Collection name - * @param string $toCollectionName New name of the collection - * @param ?string $toDatabaseName New database name of the collection. Defaults to the original database. - * @param array $options Additional options + * @param string $fromCollectionName Collection name + * @param string $toCollectionName New name of the collection + * @param string|null $toDatabaseName New database name of the collection. Defaults to the original database. + * @param array $options Additional options * @return array|object Command result document * @throws UnsupportedException if options are unsupported on the selected server * @throws InvalidArgumentException for parameter/option parsing errors @@ -537,7 +534,7 @@ public function renameCollection(string $fromCollectionName, string $toCollectio * @return Collection * @throws InvalidArgumentException for parameter/option parsing errors */ - public function selectCollection($collectionName, array $options = []) + public function selectCollection(string $collectionName, array $options = []) { $options += [ 'readConcern' => $this->readConcern, diff --git a/src/Exception/BadMethodCallException.php b/src/Exception/BadMethodCallException.php index 99dcd6a72..b140ff3ae 100644 --- a/src/Exception/BadMethodCallException.php +++ b/src/Exception/BadMethodCallException.php @@ -29,7 +29,7 @@ class BadMethodCallException extends BaseBadMethodCallException implements Excep * @param string $class Class name * @return self */ - public static function classIsImmutable($class) + public static function classIsImmutable(string $class) { return new static(sprintf('%s is immutable', $class)); } @@ -40,7 +40,7 @@ public static function classIsImmutable($class) * @param string $method Method name * @return self */ - public static function unacknowledgedWriteResultAccess($method) + public static function unacknowledgedWriteResultAccess(string $method) { return new static(sprintf('%s should not be called for an unacknowledged write result', $method)); } diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 8be0de2bb..34f4cc5d9 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -36,7 +36,7 @@ class InvalidArgumentException extends DriverInvalidArgumentException implements * @param string|string[] $expectedType Expected type * @return self */ - public static function invalidType($name, $value, $expectedType) + public static function invalidType(string $name, $value, $expectedType) { if (is_array($expectedType)) { switch (count($expectedType)) { diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php index cdf1cddc3..33f6616a7 100644 --- a/src/GridFS/Bucket.php +++ b/src/GridFS/Bucket.php @@ -32,7 +32,6 @@ use MongoDB\Model\BSONArray; use MongoDB\Model\BSONDocument; use MongoDB\Operation\Find; -use stdClass; use function array_intersect_key; use function fopen; @@ -137,7 +136,7 @@ class Bucket * @param array $options Bucket options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct(Manager $manager, $databaseName, array $options = []) + public function __construct(Manager $manager, string $databaseName, array $options = []) { $options += [ 'bucketName' => self::$defaultBucketName, @@ -178,7 +177,7 @@ public function __construct(Manager $manager, $databaseName, array $options = [] } $this->manager = $manager; - $this->databaseName = (string) $databaseName; + $this->databaseName = $databaseName; $this->bucketName = $options['bucketName']; $this->chunkSizeBytes = $options['chunkSizeBytes']; $this->disableMD5 = $options['disableMD5']; @@ -282,7 +281,7 @@ public function downloadToStream($id, $destination) * @throws StreamException if the file could not be uploaded * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function downloadToStreamByName($filename, $destination, array $options = []) + public function downloadToStreamByName(string $filename, $destination, array $options = []) { if (! is_resource($destination) || get_resource_type($destination) != "stream") { throw InvalidArgumentException::invalidType('$destination', $destination, 'resource'); @@ -517,7 +516,7 @@ public function openDownloadStream($id) * @throws FileNotFoundException if no file could be selected * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function openDownloadStreamByName($filename, array $options = []) + public function openDownloadStreamByName(string $filename, array $options = []) { $options += ['revision' => -1]; @@ -550,7 +549,7 @@ public function openDownloadStreamByName($filename, array $options = []) * @param array $options Upload options * @return resource */ - public function openUploadStream($filename, array $options = []) + public function openUploadStream(string $filename, array $options = []) { $options += ['chunkSizeBytes' => $this->chunkSizeBytes]; @@ -574,7 +573,7 @@ public function openUploadStream($filename, array $options = []) * @throws FileNotFoundException if no file could be selected * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function rename($id, $newFilename) + public function rename($id, string $newFilename) { $updateResult = $this->collectionWrapper->updateFilenameForId($id, $newFilename); @@ -620,7 +619,7 @@ public function rename($id, $newFilename) * @throws StreamException if the file could not be uploaded * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function uploadFromStream($filename, $source, array $options = []) + public function uploadFromStream(string $filename, $source, array $options = []) { if (! is_resource($source) || get_resource_type($source) != "stream") { throw InvalidArgumentException::invalidType('$source', $source, 'resource'); @@ -640,10 +639,9 @@ public function uploadFromStream($filename, $source, array $options = []) /** * Creates a path for an existing GridFS file. * - * @param stdClass $file GridFS file document - * @return string + * @param object $file GridFS file document */ - private function createPathForFile(stdClass $file) + private function createPathForFile(object $file): string { if (! is_object($file->_id) || method_exists($file->_id, '__toString')) { $id = (string) $file->_id; @@ -662,10 +660,8 @@ private function createPathForFile(stdClass $file) /** * Creates a path for a new GridFS file, which does not yet have an ID. - * - * @return string */ - private function createPathForUpload() + private function createPathForUpload(): string { return sprintf( '%s://%s/%s.files', @@ -677,10 +673,8 @@ private function createPathForUpload() /** * Returns the names of the files collection. - * - * @return string */ - private function getFilesNamespace() + private function getFilesNamespace(): string { return sprintf('%s.%s.files', $this->databaseName, $this->bucketName); } @@ -692,10 +686,9 @@ private function getFilesNamespace() * respect the Bucket's type map. * * @param resource $stream GridFS stream - * @return stdClass * @throws InvalidArgumentException */ - private function getRawFileDocumentForStream($stream) + private function getRawFileDocumentForStream($stream): object { if (! is_resource($stream) || get_resource_type($stream) != "stream") { throw InvalidArgumentException::invalidType('$stream', $stream, 'resource'); @@ -713,10 +706,10 @@ private function getRawFileDocumentForStream($stream) /** * Opens a readable stream for the GridFS file. * - * @param stdClass $file GridFS file document + * @param object $file GridFS file document * @return resource */ - private function openDownloadStreamByFile(stdClass $file) + private function openDownloadStreamByFile(object $file) { $path = $this->createPathForFile($file); $context = stream_context_create([ @@ -732,7 +725,7 @@ private function openDownloadStreamByFile(stdClass $file) /** * Registers the GridFS stream wrapper if it is not already registered. */ - private function registerStreamWrapper() + private function registerStreamWrapper(): void { if (in_array(self::$streamWrapperProtocol, stream_get_wrappers())) { return; diff --git a/src/GridFS/CollectionWrapper.php b/src/GridFS/CollectionWrapper.php index 7b58a4fb7..f4d4d76dc 100644 --- a/src/GridFS/CollectionWrapper.php +++ b/src/GridFS/CollectionWrapper.php @@ -25,7 +25,6 @@ use MongoDB\Exception\InvalidArgumentException; use MongoDB\UpdateResult; use MultipleIterator; -use stdClass; use function abs; use function count; @@ -64,10 +63,10 @@ class CollectionWrapper * @param array $collectionOptions Collection options * @throws InvalidArgumentException */ - public function __construct(Manager $manager, $databaseName, $bucketName, array $collectionOptions = []) + public function __construct(Manager $manager, string $databaseName, string $bucketName, array $collectionOptions = []) { - $this->databaseName = (string) $databaseName; - $this->bucketName = (string) $bucketName; + $this->databaseName = $databaseName; + $this->bucketName = $bucketName; $this->filesCollection = new Collection($manager, $databaseName, sprintf('%s.files', $bucketName), $collectionOptions); $this->chunksCollection = new Collection($manager, $databaseName, sprintf('%s.chunks', $bucketName), $collectionOptions); @@ -78,7 +77,7 @@ public function __construct(Manager $manager, $databaseName, $bucketName, array * * @param mixed $id */ - public function deleteChunksByFilesId($id) + public function deleteChunksByFilesId($id): void { $this->chunksCollection->deleteMany(['files_id' => $id]); } @@ -88,7 +87,7 @@ public function deleteChunksByFilesId($id) * * @param mixed $id */ - public function deleteFileAndChunksById($id) + public function deleteFileAndChunksById($id): void { $this->filesCollection->deleteOne(['_id' => $id]); $this->chunksCollection->deleteMany(['files_id' => $id]); @@ -97,7 +96,7 @@ public function deleteFileAndChunksById($id) /** * Drops the GridFS files and chunks collections. */ - public function dropCollections() + public function dropCollections(): void { $this->filesCollection->drop(['typeMap' => []]); $this->chunksCollection->drop(['typeMap' => []]); @@ -108,9 +107,8 @@ public function dropCollections() * * @param mixed $id File ID * @param integer $fromChunk Starting chunk (inclusive) - * @return Cursor */ - public function findChunksByFileId($id, $fromChunk = 0) + public function findChunksByFileId($id, int $fromChunk = 0): Cursor { return $this->chunksCollection->find( [ @@ -138,14 +136,11 @@ public function findChunksByFileId($id, $fromChunk = 0) * * @see Bucket::downloadToStreamByName() * @see Bucket::openDownloadStreamByName() - * @param string $filename - * @param integer $revision - * @return stdClass|null */ - public function findFileByFilenameAndRevision($filename, $revision) + public function findFileByFilenameAndRevision(string $filename, int $revision): ?object { - $filename = (string) $filename; - $revision = (integer) $revision; + $filename = $filename; + $revision = $revision; if ($revision < 0) { $skip = abs($revision) - 1; @@ -169,9 +164,8 @@ public function findFileByFilenameAndRevision($filename, $revision) * Finds a GridFS file document for a given ID. * * @param mixed $id - * @return stdClass|null */ - public function findFileById($id) + public function findFileById($id): ?object { return $this->filesCollection->findOne( ['_id' => $id], @@ -204,42 +198,22 @@ public function findOneFile($filter, array $options = []) return $this->filesCollection->findOne($filter, $options); } - /** - * Return the bucket name. - * - * @return string - */ - public function getBucketName() + public function getBucketName(): string { return $this->bucketName; } - /** - * Return the chunks collection. - * - * @return Collection - */ - public function getChunksCollection() + public function getChunksCollection(): Collection { return $this->chunksCollection; } - /** - * Return the database name. - * - * @return string - */ - public function getDatabaseName() + public function getDatabaseName(): string { return $this->databaseName; } - /** - * Return the files collection. - * - * @return Collection - */ - public function getFilesCollection() + public function getFilesCollection(): Collection { return $this->filesCollection; } @@ -249,7 +223,7 @@ public function getFilesCollection() * * @param array|object $chunk Chunk document */ - public function insertChunk($chunk) + public function insertChunk($chunk): void { if (! $this->checkedIndexes) { $this->ensureIndexes(); @@ -265,7 +239,7 @@ public function insertChunk($chunk) * * @param array|object $file File document */ - public function insertFile($file) + public function insertFile($file): void { if (! $this->checkedIndexes) { $this->ensureIndexes(); @@ -277,22 +251,20 @@ public function insertFile($file) /** * Updates the filename field in the file document for a given ID. * - * @param mixed $id - * @param string $filename - * @return UpdateResult + * @param mixed $id */ - public function updateFilenameForId($id, $filename) + public function updateFilenameForId($id, string $filename): UpdateResult { return $this->filesCollection->updateOne( ['_id' => $id], - ['$set' => ['filename' => (string) $filename]] + ['$set' => ['filename' => $filename]] ); } /** * Create an index on the chunks collection if it does not already exist. */ - private function ensureChunksIndex() + private function ensureChunksIndex(): void { $expectedIndex = ['files_id' => 1, 'n' => 1]; @@ -308,7 +280,7 @@ private function ensureChunksIndex() /** * Create an index on the files collection if it does not already exist. */ - private function ensureFilesIndex() + private function ensureFilesIndex(): void { $expectedIndex = ['filename' => 1, 'uploadDate' => 1]; @@ -327,7 +299,7 @@ private function ensureFilesIndex() * This method is called once before the first write operation on a GridFS * bucket. Indexes are only be created if the files collection is empty. */ - private function ensureIndexes() + private function ensureIndexes(): void { if ($this->checkedIndexes) { return; @@ -375,10 +347,8 @@ private function indexKeysMatch(array $expectedKeys, array $actualKeys): bool /** * Returns whether the files collection is empty. - * - * @return boolean */ - private function isFilesCollectionEmpty() + private function isFilesCollectionEmpty(): bool { return null === $this->filesCollection->findOne([], [ 'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY), diff --git a/src/GridFS/Exception/CorruptFileException.php b/src/GridFS/Exception/CorruptFileException.php index c68ceec95..7879cb1ec 100644 --- a/src/GridFS/Exception/CorruptFileException.php +++ b/src/GridFS/Exception/CorruptFileException.php @@ -29,7 +29,7 @@ class CorruptFileException extends RuntimeException * @param integer $expectedIndex Expected index number * @return self */ - public static function missingChunk($expectedIndex) + public static function missingChunk(int $expectedIndex) { return new static(sprintf('Chunk not found for index "%d"', $expectedIndex)); } @@ -41,7 +41,7 @@ public static function missingChunk($expectedIndex) * @param integer $expectedIndex Expected index number * @return self */ - public static function unexpectedIndex($index, $expectedIndex) + public static function unexpectedIndex(int $index, int $expectedIndex) { return new static(sprintf('Expected chunk to have index "%d" but found "%d"', $expectedIndex, $index)); } @@ -53,7 +53,7 @@ public static function unexpectedIndex($index, $expectedIndex) * @param integer $expectedSize Expected size * @return self */ - public static function unexpectedSize($size, $expectedSize) + public static function unexpectedSize(int $size, int $expectedSize) { return new static(sprintf('Expected chunk to have size "%d" but found "%d"', $expectedSize, $size)); } diff --git a/src/GridFS/Exception/FileNotFoundException.php b/src/GridFS/Exception/FileNotFoundException.php index ff9c2c7eb..5d0f5d5c5 100644 --- a/src/GridFS/Exception/FileNotFoundException.php +++ b/src/GridFS/Exception/FileNotFoundException.php @@ -33,7 +33,7 @@ class FileNotFoundException extends RuntimeException * @param string $namespace Namespace for the files collection * @return self */ - public static function byFilenameAndRevision($filename, $revision, $namespace) + public static function byFilenameAndRevision(string $filename, int $revision, string $namespace) { return new static(sprintf('File with name "%s" and revision "%d" not found in "%s"', $filename, $revision, $namespace)); } @@ -45,7 +45,7 @@ public static function byFilenameAndRevision($filename, $revision, $namespace) * @param string $namespace Namespace for the files collection * @return self */ - public static function byId($id, $namespace) + public static function byId($id, string $namespace) { $json = toJSON(fromPHP(['_id' => $id])); diff --git a/src/GridFS/ReadableStream.php b/src/GridFS/ReadableStream.php index 5a5b1ec3b..9672b803f 100644 --- a/src/GridFS/ReadableStream.php +++ b/src/GridFS/ReadableStream.php @@ -20,7 +20,6 @@ use MongoDB\Driver\CursorInterface; use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\Exception\CorruptFileException; -use stdClass; use function ceil; use function floor; @@ -58,7 +57,7 @@ class ReadableStream /** @var float|integer */ private $expectedLastChunkSize = 0; - /** @var stdClass */ + /** @var object */ private $file; /** @var integer */ @@ -71,10 +70,10 @@ class ReadableStream * Constructs a readable GridFS stream. * * @param CollectionWrapper $collectionWrapper GridFS collection wrapper - * @param stdClass $file GridFS file document + * @param object $file GridFS file document * @throws CorruptFileException */ - public function __construct(CollectionWrapper $collectionWrapper, stdClass $file) + public function __construct(CollectionWrapper $collectionWrapper, object $file) { if (! isset($file->chunkSize) || ! is_integer($file->chunkSize) || $file->chunkSize < 1) { throw new CorruptFileException('file.chunkSize is not an integer >= 1'); @@ -89,8 +88,8 @@ public function __construct(CollectionWrapper $collectionWrapper, stdClass $file } $this->file = $file; - $this->chunkSize = (integer) $file->chunkSize; - $this->length = (integer) $file->length; + $this->chunkSize = $file->chunkSize; + $this->length = $file->length; $this->collectionWrapper = $collectionWrapper; @@ -106,7 +105,7 @@ public function __construct(CollectionWrapper $collectionWrapper, stdClass $file * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo * @return array */ - public function __debugInfo() + public function __debugInfo(): array { return [ 'bucketName' => $this->collectionWrapper->getBucketName(), @@ -115,37 +114,25 @@ public function __debugInfo() ]; } - public function close() + public function close(): void { // Nothing to do } - /** - * Return the stream's file document. - * - * @return stdClass - */ - public function getFile() + public function getFile(): object { return $this->file; } - /** - * Return the stream's size in bytes. - * - * @return integer - */ - public function getSize() + public function getSize(): int { return $this->length; } /** * Return whether the current read position is at the end of the stream. - * - * @return boolean */ - public function isEOF() + public function isEOF(): bool { if ($this->chunkOffset === $this->numChunks - 1) { return $this->bufferOffset >= $this->expectedLastChunkSize; @@ -161,10 +148,9 @@ public function isEOF() * if data is not available to be read. * * @param integer $length Number of bytes to read - * @return string * @throws InvalidArgumentException if $length is negative */ - public function readBytes($length) + public function readBytes(int $length): string { if ($length < 0) { throw new InvalidArgumentException(sprintf('$length must be >= 0; given: %d', $length)); @@ -196,10 +182,9 @@ public function readBytes($length) /** * Seeks the chunk and buffer offsets for the next read operation. * - * @param integer $offset * @throws InvalidArgumentException if $offset is out of range */ - public function seek($offset) + public function seek(int $offset): void { if ($offset < 0 || $offset > $this->file->length) { throw new InvalidArgumentException(sprintf('$offset must be >= 0 and <= %d; given: %d', $this->file->length, $offset)); @@ -247,10 +232,8 @@ public function seek($offset) * Return the current position of the stream. * * This is the offset within the stream where the next byte would be read. - * - * @return integer */ - public function tell() + public function tell(): int { return ($this->chunkOffset * $this->chunkSize) + $this->bufferOffset; } @@ -261,7 +244,7 @@ public function tell() * @return boolean Whether there was a current chunk to read * @throws CorruptFileException if an expected chunk could not be read successfully */ - private function initBufferFromCurrentChunk() + private function initBufferFromCurrentChunk(): bool { if ($this->chunkOffset === 0 && $this->numChunks === 0) { return false; @@ -298,7 +281,7 @@ private function initBufferFromCurrentChunk() * @return boolean Whether there was a next chunk to read * @throws CorruptFileException if an expected chunk could not be read successfully */ - private function initBufferFromNextChunk() + private function initBufferFromNextChunk(): bool { if ($this->chunkOffset === $this->numChunks - 1) { return false; @@ -314,7 +297,7 @@ private function initBufferFromNextChunk() /** * Initializes the chunk iterator starting from the current offset. */ - private function initChunksIterator() + private function initChunksIterator(): void { $this->chunksIterator = $this->collectionWrapper->findChunksByFileId($this->file->_id, $this->chunkOffset); $this->chunksIterator->rewind(); diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index 3507708cb..268c47ea7 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -18,7 +18,6 @@ namespace MongoDB\GridFS; use MongoDB\BSON\UTCDateTime; -use stdClass; use function explode; use function in_array; @@ -64,10 +63,8 @@ public function __destruct() /** * Return the stream's file document. - * - * @return stdClass */ - public function getFile() + public function getFile(): object { return $this->stream->getFile(); } @@ -77,7 +74,7 @@ public function getFile() * * @param string $protocol Protocol to use for stream_wrapper_register() */ - public static function register($protocol = 'gridfs') + public static function register(string $protocol = 'gridfs'): void { if (in_array($protocol, stream_get_wrappers())) { stream_wrapper_unregister($protocol); @@ -91,7 +88,7 @@ public static function register($protocol = 'gridfs') * * @see https://php.net/manual/en/streamwrapper.stream-close.php */ - public function stream_close() + public function stream_close(): void { if (! $this->stream) { return; @@ -104,9 +101,8 @@ public function stream_close() * Returns whether the file pointer is at the end of the stream. * * @see https://php.net/manual/en/streamwrapper.stream-eof.php - * @return boolean */ - public function stream_eof() + public function stream_eof(): bool { if (! $this->stream instanceof ReadableStream) { return false; @@ -119,13 +115,12 @@ public function stream_eof() * Opens the stream. * * @see https://php.net/manual/en/streamwrapper.stream-open.php - * @param string $path Path to the file resource - * @param string $mode Mode used to open the file (only "r" and "w" are supported) - * @param integer $options Additional flags set by the streams API - * @param string $openedPath Not used - * @return boolean + * @param string $path Path to the file resource + * @param string $mode Mode used to open the file (only "r" and "w" are supported) + * @param integer $options Additional flags set by the streams API + * @param string|null $openedPath Not used */ - public function stream_open($path, $mode, $options, &$openedPath) + public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool { $this->initProtocol($path); $this->mode = $mode; @@ -149,9 +144,8 @@ public function stream_open($path, $mode, $options, &$openedPath) * * @see https://php.net/manual/en/streamwrapper.stream-read.php * @param integer $length Number of bytes to read - * @return string */ - public function stream_read($length) + public function stream_read(int $length): string { if (! $this->stream instanceof ReadableStream) { return ''; @@ -168,7 +162,7 @@ public function stream_read($length) * @param integer $whence One of SEEK_SET, SEEK_CUR, or SEEK_END * @return boolean True if the position was updated and false otherwise */ - public function stream_seek($offset, $whence = SEEK_SET) + public function stream_seek(int $offset, int $whence = SEEK_SET): bool { $size = $this->stream->getSize(); @@ -198,9 +192,8 @@ public function stream_seek($offset, $whence = SEEK_SET) * Return information about the stream. * * @see https://php.net/manual/en/streamwrapper.stream-stat.php - * @return array */ - public function stream_stat() + public function stream_stat(): array { $stat = $this->getStatTemplate(); @@ -230,7 +223,7 @@ public function stream_stat() * @see https://php.net/manual/en/streamwrapper.stream-tell.php * @return integer The current position of the stream */ - public function stream_tell() + public function stream_tell(): int { return $this->stream->tell(); } @@ -242,7 +235,7 @@ public function stream_tell() * @param string $data Data to write * @return integer The number of bytes written */ - public function stream_write($data) + public function stream_write(string $data): int { if (! $this->stream instanceof WritableStream) { return 0; @@ -253,10 +246,8 @@ public function stream_write($data) /** * Returns a stat template with default values. - * - * @return array */ - private function getStatTemplate() + private function getStatTemplate(): array { return [ // phpcs:disable Squiz.Arrays.ArrayDeclaration.IndexNoNewline @@ -281,9 +272,8 @@ private function getStatTemplate() * Initialize the protocol from the given path. * * @see StreamWrapper::stream_open() - * @param string $path */ - private function initProtocol($path) + private function initProtocol(string $path): void { $parts = explode('://', $path, 2); $this->protocol = $parts[0] ?: 'gridfs'; @@ -293,9 +283,8 @@ private function initProtocol($path) * Initialize the internal stream for reading. * * @see StreamWrapper::stream_open() - * @return boolean */ - private function initReadableStream() + private function initReadableStream(): bool { $context = stream_context_get_options($this->context); @@ -311,9 +300,8 @@ private function initReadableStream() * Initialize the internal stream for writing. * * @see StreamWrapper::stream_open() - * @return boolean */ - private function initWritableStream() + private function initWritableStream(): bool { $context = stream_context_get_options($this->context); diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php index d38d39f8e..b80a8ce6b 100644 --- a/src/GridFS/WritableStream.php +++ b/src/GridFS/WritableStream.php @@ -22,7 +22,6 @@ use MongoDB\BSON\UTCDateTime; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Exception\InvalidArgumentException; -use stdClass; use function array_intersect_key; use function hash_final; @@ -103,7 +102,7 @@ class WritableStream * @param array $options Upload options * @throws InvalidArgumentException */ - public function __construct(CollectionWrapper $collectionWrapper, $filename, array $options = []) + public function __construct(CollectionWrapper $collectionWrapper, string $filename, array $options = []) { $options += [ '_id' => new ObjectId(), @@ -146,7 +145,7 @@ public function __construct(CollectionWrapper $collectionWrapper, $filename, arr $this->file = [ '_id' => $options['_id'], 'chunkSize' => $this->chunkSize, - 'filename' => (string) $filename, + 'filename' => $filename, ] + array_intersect_key($options, ['aliases' => 1, 'contentType' => 1, 'metadata' => 1]); } @@ -154,9 +153,8 @@ public function __construct(CollectionWrapper $collectionWrapper, $filename, arr * Return internal properties for debugging purposes. * * @see https://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo - * @return array */ - public function __debugInfo() + public function __debugInfo(): array { return [ 'bucketName' => $this->collectionWrapper->getBucketName(), @@ -168,7 +166,7 @@ public function __debugInfo() /** * Closes an active stream and flushes all buffered data to GridFS. */ - public function close() + public function close(): void { if ($this->isClosed) { // TODO: Should this be an error condition? e.g. BadMethodCallException @@ -185,10 +183,8 @@ public function close() /** * Return the stream's file document. - * - * @return stdClass */ - public function getFile() + public function getFile(): object { return (object) $this->file; } @@ -197,10 +193,8 @@ public function getFile() * Return the stream's size in bytes. * * Note: this value will increase as more data is written to the stream. - * - * @return integer */ - public function getSize() + public function getSize(): int { return $this->length + strlen($this->buffer); } @@ -213,9 +207,8 @@ public function getSize() * always the end of the stream. * * @see WritableStream::getSize() - * @return integer */ - public function tell() + public function tell(): int { return $this->getSize(); } @@ -227,13 +220,12 @@ public function tell() * which point a chunk document will be inserted and the buffer reset. * * @param string $data Binary data to write - * @return integer */ - public function writeBytes($data) + public function writeBytes(string $data): int { if ($this->isClosed) { // TODO: Should this be an error condition? e.g. BadMethodCallException - return; + return 0; } $bytesRead = 0; @@ -251,7 +243,7 @@ public function writeBytes($data) return $bytesRead; } - private function abort() + private function abort(): void { try { $this->collectionWrapper->deleteChunksByFilesId($this->file['_id']); @@ -285,7 +277,7 @@ private function fileCollectionInsert() return $this->file['_id']; } - private function insertChunkFromBuffer() + private function insertChunkFromBuffer(): void { if (strlen($this->buffer) == 0) { return; diff --git a/src/InsertManyResult.php b/src/InsertManyResult.php index 5dc29a8d2..87fd60eef 100644 --- a/src/InsertManyResult.php +++ b/src/InsertManyResult.php @@ -28,16 +28,12 @@ class InsertManyResult /** @var WriteResult */ private $writeResult; - /** @var mixed[] */ + /** @var array */ private $insertedIds; /** @var boolean */ private $isAcknowledged; - /** - * @param WriteResult $writeResult - * @param mixed[] $insertedIds - */ public function __construct(WriteResult $writeResult, array $insertedIds) { $this->writeResult = $writeResult; @@ -72,7 +68,7 @@ public function getInsertedCount() * field value. Any driver-generated ID will be a MongoDB\BSON\ObjectId * instance. * - * @return mixed[] + * @return array */ public function getInsertedIds() { diff --git a/src/InsertOneResult.php b/src/InsertOneResult.php index 32a14a1e3..4376b6bdf 100644 --- a/src/InsertOneResult.php +++ b/src/InsertOneResult.php @@ -35,8 +35,7 @@ class InsertOneResult private $isAcknowledged; /** - * @param WriteResult $writeResult - * @param mixed $insertedId + * @param mixed $insertedId */ public function __construct(WriteResult $writeResult, $insertedId) { diff --git a/src/MapReduceResult.php b/src/MapReduceResult.php index fe2127902..d7ef777a3 100644 --- a/src/MapReduceResult.php +++ b/src/MapReduceResult.php @@ -79,7 +79,7 @@ public function getCounts() */ public function getExecutionTimeMS() { - return (integer) $this->executionTimeMS; + return $this->executionTimeMS; } /** diff --git a/src/Model/BSONArray.php b/src/Model/BSONArray.php index 74d0caf40..a87505f29 100644 --- a/src/Model/BSONArray.php +++ b/src/Model/BSONArray.php @@ -51,7 +51,6 @@ public function __clone() * * @see https://php.net/oop5.magic#object.set-state * @see https://php.net/var-export - * @param array $properties * @return self */ public static function __set_state(array $properties) diff --git a/src/Model/BSONDocument.php b/src/Model/BSONDocument.php index af439f8ad..8fc04e84f 100644 --- a/src/Model/BSONDocument.php +++ b/src/Model/BSONDocument.php @@ -50,11 +50,8 @@ public function __clone() * by default. * * @see https://php.net/arrayobject.construct - * @param array $input - * @param integer $flags - * @param string $iteratorClass */ - public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $iteratorClass = 'ArrayIterator') + public function __construct(array $input = [], int $flags = ArrayObject::ARRAY_AS_PROPS, string $iteratorClass = 'ArrayIterator') { parent::__construct($input, $flags, $iteratorClass); } @@ -64,7 +61,6 @@ public function __construct($input = [], $flags = ArrayObject::ARRAY_AS_PROPS, $ * * @see https://php.net/oop5.magic#object.set-state * @see https://php.net/var-export - * @param array $properties * @return self */ public static function __set_state(array $properties) diff --git a/src/Model/BSONIterator.php b/src/Model/BSONIterator.php index 5c086b81a..2bddc264c 100644 --- a/src/Model/BSONIterator.php +++ b/src/Model/BSONIterator.php @@ -68,7 +68,7 @@ class BSONIterator implements Iterator * @param array $options Iterator options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($data, array $options = []) + public function __construct(string $data, array $options = []) { if (isset($options['typeMap']) && ! is_array($options['typeMap'])) { throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); @@ -130,15 +130,14 @@ public function rewind() /** * @see https://php.net/iterator.valid - * @return boolean */ #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { return $this->current !== null; } - private function advance() + private function advance(): void { if ($this->position === $this->bufferLength) { return; diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php index 0e54dc2c8..f2a7dd25b 100644 --- a/src/Model/CachingIterator.php +++ b/src/Model/CachingIterator.php @@ -72,10 +72,8 @@ public function __construct(Traversable $traversable) /** * @see https://php.net/countable.count - * @return integer */ - #[ReturnTypeWillChange] - public function count() + public function count(): int { $this->exhaustIterator(); @@ -108,10 +106,8 @@ public function key() /** * @see https://php.net/iterator.next - * @return void */ - #[ReturnTypeWillChange] - public function next() + public function next(): void { if (! $this->iteratorExhausted) { $this->iteratorAdvanced = true; @@ -127,10 +123,8 @@ public function next() /** * @see https://php.net/iterator.rewind - * @return void */ - #[ReturnTypeWillChange] - public function rewind() + public function rewind(): void { /* If the iterator has advanced, exhaust it now so that future iteration * can rely on the cache. @@ -144,10 +138,8 @@ public function rewind() /** * @see https://php.net/iterator.valid - * @return boolean */ - #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { return $this->key() !== null; } @@ -155,7 +147,7 @@ public function valid() /** * Ensures that the inner iterator is fully consumed and cached. */ - private function exhaustIterator() + private function exhaustIterator(): void { while (! $this->iteratorExhausted) { $this->next(); @@ -165,7 +157,7 @@ private function exhaustIterator() /** * Stores the current item in the cache. */ - private function storeCurrentItem() + private function storeCurrentItem(): void { if (! $this->iterator->valid()) { return; diff --git a/src/Model/CallbackIterator.php b/src/Model/CallbackIterator.php index a5abec9c1..8e3c68d0c 100644 --- a/src/Model/CallbackIterator.php +++ b/src/Model/CallbackIterator.php @@ -64,30 +64,24 @@ public function key() /** * @see https://php.net/iterator.next - * @return void */ - #[ReturnTypeWillChange] - public function next() + public function next(): void { $this->iterator->next(); } /** * @see https://php.net/iterator.rewind - * @return void */ - #[ReturnTypeWillChange] - public function rewind() + public function rewind(): void { $this->iterator->rewind(); } /** * @see https://php.net/iterator.valid - * @return boolean */ - #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { return $this->iterator->valid(); } diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index 307a68edc..85fba283d 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -71,12 +71,9 @@ class ChangeStreamIterator extends IteratorIterator implements CommandSubscriber /** * @internal - * @param Cursor $cursor - * @param integer $firstBatchSize * @param array|object|null $initialResumeToken - * @param object|null $postBatchResumeToken */ - public function __construct(Cursor $cursor, $firstBatchSize, $initialResumeToken, $postBatchResumeToken) + public function __construct(Cursor $cursor, int $firstBatchSize, $initialResumeToken, ?object $postBatchResumeToken) { if (! is_integer($firstBatchSize)) { throw InvalidArgumentException::invalidType('$firstBatchSize', $firstBatchSize, 'integer'); @@ -180,10 +177,8 @@ public function key() /** * @see https://php.net/iteratoriterator.rewind - * @return void */ - #[ReturnTypeWillChange] - public function next() + public function next(): void { /* Determine if advancing the iterator will execute a getMore command * (i.e. we are already positioned at the end of the current batch). If @@ -208,10 +203,8 @@ public function next() /** * @see https://php.net/iteratoriterator.rewind - * @return void */ - #[ReturnTypeWillChange] - public function rewind() + public function rewind(): void { if ($this->isRewindNop) { return; @@ -223,10 +216,8 @@ public function rewind() /** * @see https://php.net/iteratoriterator.valid - * @return boolean */ - #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { return $this->isValid; } @@ -270,10 +261,8 @@ private function extractResumeToken($document) /** * Return whether the iterator is positioned at the end of the batch. - * - * @return boolean */ - private function isAtEndOfBatch() + private function isAtEndOfBatch(): bool { return $this->batchPosition + 1 >= $this->batchSize; } @@ -282,9 +271,8 @@ private function isAtEndOfBatch() * Perform housekeeping after an iteration event. * * @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#updating-the-cached-resume-token - * @param boolean $incrementBatchPosition */ - private function onIteration($incrementBatchPosition) + private function onIteration(bool $incrementBatchPosition): void { $this->isValid = parent::valid(); diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php index 0513125ca..6722978bc 100644 --- a/src/Model/CollectionInfo.php +++ b/src/Model/CollectionInfo.php @@ -86,8 +86,6 @@ public function getCappedSize() /** * Return information about the _id index for the collection. - * - * @return array */ public function getIdIndex(): array { @@ -98,7 +96,6 @@ public function getIdIndex(): array * Return the "info" property of the server response. * * @see https://mongodb.com/docs/manual/reference/command/listCollections/#output - * @return array */ public function getInfo(): array { @@ -131,7 +128,6 @@ public function getOptions() * Return the collection type. * * @see https://mongodb.com/docs/manual/reference/command/listCollections/#output - * @return string */ public function getType(): string { diff --git a/src/Model/CollectionInfoCommandIterator.php b/src/Model/CollectionInfoCommandIterator.php index 316b67fb0..96c2d73a9 100644 --- a/src/Model/CollectionInfoCommandIterator.php +++ b/src/Model/CollectionInfoCommandIterator.php @@ -18,7 +18,6 @@ namespace MongoDB\Model; use IteratorIterator; -use ReturnTypeWillChange; use Traversable; /** @@ -37,10 +36,7 @@ class CollectionInfoCommandIterator extends IteratorIterator implements Collecti /** @var string|null */ private $databaseName; - /** - * @param string|null $databaseName - */ - public function __construct(Traversable $iterator, $databaseName = null) + public function __construct(Traversable $iterator, ?string $databaseName = null) { parent::__construct($iterator); @@ -52,10 +48,8 @@ public function __construct(Traversable $iterator, $databaseName = null) * * @see CollectionInfoIterator::current() * @see https://php.net/iterator.current - * @return CollectionInfo */ - #[ReturnTypeWillChange] - public function current() + public function current(): CollectionInfo { $info = parent::current(); diff --git a/src/Model/DatabaseInfoLegacyIterator.php b/src/Model/DatabaseInfoLegacyIterator.php index c6f5f0842..2fb8e88a5 100644 --- a/src/Model/DatabaseInfoLegacyIterator.php +++ b/src/Model/DatabaseInfoLegacyIterator.php @@ -17,8 +17,6 @@ namespace MongoDB\Model; -use ReturnTypeWillChange; - use function current; use function key; use function next; @@ -39,9 +37,6 @@ class DatabaseInfoLegacyIterator implements DatabaseInfoIterator /** @var array */ private $databases; - /** - * @param array $databases - */ public function __construct(array $databases) { $this->databases = $databases; @@ -52,9 +47,8 @@ public function __construct(array $databases) * * @see DatabaseInfoIterator::current() * @see https://php.net/iterator.current - * @return DatabaseInfo */ - public function current() + public function current(): DatabaseInfo { return new DatabaseInfo(current($this->databases)); } @@ -63,10 +57,8 @@ public function current() * Return the key of the current element. * * @see https://php.net/iterator.key - * @return integer */ - #[ReturnTypeWillChange] - public function key() + public function key(): int { return key($this->databases); } @@ -75,10 +67,8 @@ public function key() * Move forward to next element. * * @see https://php.net/iterator.next - * @return void */ - #[ReturnTypeWillChange] - public function next() + public function next(): void { next($this->databases); } @@ -87,10 +77,8 @@ public function next() * Rewind the Iterator to the first element. * * @see https://php.net/iterator.rewind - * @return void */ - #[ReturnTypeWillChange] - public function rewind() + public function rewind(): void { reset($this->databases); } @@ -99,10 +87,8 @@ public function rewind() * Checks if current position is valid. * * @see https://php.net/iterator.valid - * @return boolean */ - #[ReturnTypeWillChange] - public function valid() + public function valid(): bool { return key($this->databases) !== null; } diff --git a/src/Model/IndexInfoIteratorIterator.php b/src/Model/IndexInfoIteratorIterator.php index fcdcbf041..f0a35baf0 100644 --- a/src/Model/IndexInfoIteratorIterator.php +++ b/src/Model/IndexInfoIteratorIterator.php @@ -18,7 +18,6 @@ namespace MongoDB\Model; use IteratorIterator; -use ReturnTypeWillChange; use Traversable; use function array_key_exists; @@ -41,10 +40,7 @@ class IndexInfoIteratorIterator extends IteratorIterator implements IndexInfoIte /** @var string|null $ns */ private $ns; - /** - * @param string|null $ns - */ - public function __construct(Traversable $iterator, $ns = null) + public function __construct(Traversable $iterator, ?string $ns = null) { parent::__construct($iterator); @@ -56,10 +52,8 @@ public function __construct(Traversable $iterator, $ns = null) * * @see IndexInfoIterator::current() * @see https://php.net/iterator.current - * @return IndexInfo */ - #[ReturnTypeWillChange] - public function current() + public function current(): IndexInfo { $info = parent::current(); diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php index 5c6342b4c..65c3fc2a2 100644 --- a/src/Model/IndexInput.php +++ b/src/Model/IndexInput.php @@ -19,7 +19,6 @@ use MongoDB\BSON\Serializable; use MongoDB\Exception\InvalidArgumentException; -use ReturnTypeWillChange; use function is_array; use function is_float; @@ -77,10 +76,8 @@ public function __construct(array $index) /** * Return the index name. - * - * @return string */ - public function __toString() + public function __toString(): string { return $this->index['name']; } @@ -90,10 +87,8 @@ public function __toString() * * @see \MongoDB\Collection::createIndexes() * @see https://php.net/mongodb-bson-serializable.bsonserialize - * @return array */ - #[ReturnTypeWillChange] - public function bsonSerialize() + public function bsonSerialize(): array { return $this->index; } diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index de3c1e4f0..f529be022 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -137,7 +137,7 @@ class Aggregate implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $pipeline, array $options = []) + public function __construct(string $databaseName, ?string $collectionName, array $pipeline, array $options = []) { $expectedIndex = 0; @@ -246,8 +246,8 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr unset($options['batchSize']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = isset($collectionName) ? (string) $collectionName : null; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->pipeline = $pipeline; $this->options = $options; } @@ -256,7 +256,6 @@ public function __construct($databaseName, $collectionName, array $pipeline, arr * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return Traversable * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if read concern or write concern is used and unsupported @@ -307,7 +306,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -317,10 +315,8 @@ public function getCommandDocument(Server $server) /** * Create the aggregate command document. - * - * @return array */ - private function createCommandDocument() + private function createCommandDocument(): array { $cmd = [ 'aggregate' => $this->collectionName ?? 1, diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php index f9096c2c5..28568de25 100644 --- a/src/Operation/BulkWrite.php +++ b/src/Operation/BulkWrite.php @@ -127,7 +127,7 @@ class BulkWrite implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $operations, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $operations, array $options = []) { if (empty($operations)) { throw new InvalidArgumentException('$operations is empty'); @@ -297,8 +297,8 @@ public function __construct($databaseName, $collectionName, array $operations, a unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->operations = $operations; $this->options = $options; } @@ -307,7 +307,6 @@ public function __construct($databaseName, $collectionName, array $operations, a * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return BulkWriteResult * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -352,9 +351,8 @@ public function execute(Server $server) * Create options for constructing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php - * @return array */ - private function createBulkWriteOptions() + private function createBulkWriteOptions(): array { $options = ['ordered' => $this->options['ordered']]; @@ -375,9 +373,8 @@ private function createBulkWriteOptions() * Create options for executing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php - * @return array */ - private function createExecuteOptions() + private function createExecuteOptions(): array { $options = []; diff --git a/src/Operation/Count.php b/src/Operation/Count.php index aff947b72..b72bc34bf 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -90,7 +90,7 @@ class Count implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter = [], array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter = [], array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -132,8 +132,8 @@ public function __construct($databaseName, $collectionName, $filter = [], array unset($options['readConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->filter = $filter; $this->options = $options; } @@ -142,7 +142,6 @@ public function __construct($databaseName, $collectionName, $filter = [], array * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return integer * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if read concern is used and unsupported @@ -170,7 +169,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -180,10 +178,8 @@ public function getCommandDocument(Server $server) /** * Create the count command document. - * - * @return array */ - private function createCommandDocument() + private function createCommandDocument(): array { $cmd = ['count' => $this->collectionName]; @@ -212,9 +208,8 @@ private function createCommandDocument() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index 6e0e561f9..cc5534d28 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -93,7 +93,7 @@ class CountDocuments implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -107,8 +107,8 @@ public function __construct($databaseName, $collectionName, $filter, array $opti throw InvalidArgumentException::invalidType('"skip" option', $options['skip'], 'integer'); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->filter = $filter; $this->aggregateOptions = array_intersect_key($options, ['collation' => 1, 'comment' => 1, 'hint' => 1, 'maxTimeMS' => 1, 'readConcern' => 1, 'readPreference' => 1, 'session' => 1]); @@ -121,7 +121,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return integer * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if collation or read concern is used and unsupported @@ -146,10 +145,7 @@ public function execute(Server $server) return (integer) $result->n; } - /** - * @return Aggregate - */ - private function createAggregate() + private function createAggregate(): Aggregate { $pipeline = [ ['$match' => (object) $this->filter], diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php index 61c687730..8860a2889 100644 --- a/src/Operation/CreateCollection.php +++ b/src/Operation/CreateCollection.php @@ -142,7 +142,7 @@ class CreateCollection implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $options = []) { if (isset($options['autoIndexId']) && ! is_bool($options['autoIndexId'])) { throw InvalidArgumentException::invalidType('"autoIndexId" option', $options['autoIndexId'], 'boolean'); @@ -256,8 +256,8 @@ public function __construct($databaseName, $collectionName, array $options = []) } } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->options = $options; } @@ -265,7 +265,6 @@ public function __construct($databaseName, $collectionName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object Command result document * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ @@ -282,10 +281,8 @@ public function execute(Server $server) /** * Create the create command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = ['create' => $this->collectionName]; @@ -308,9 +305,8 @@ private function createCommand() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php index 498b8c1ef..351f25116 100644 --- a/src/Operation/CreateIndexes.php +++ b/src/Operation/CreateIndexes.php @@ -84,7 +84,7 @@ class CreateIndexes implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $indexes, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $indexes, array $options = []) { if (empty($indexes)) { throw new InvalidArgumentException('$indexes is empty'); @@ -126,8 +126,8 @@ public function __construct($databaseName, $collectionName, array $indexes, arra unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->options = $options; } @@ -135,7 +135,6 @@ public function __construct($databaseName, $collectionName, array $indexes, arra * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return string[] The names of the created indexes * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -158,9 +157,8 @@ public function execute(Server $server) * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; @@ -179,10 +177,9 @@ private function createOptions() * Create one or more indexes for the collection using the createIndexes * command. * - * @param Server $server * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - private function executeCommand(Server $server) + private function executeCommand(Server $server): void { $cmd = [ 'createIndexes' => $this->collectionName, diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php index 317abc658..a0f48fae0 100644 --- a/src/Operation/DatabaseCommand.php +++ b/src/Operation/DatabaseCommand.php @@ -65,7 +65,7 @@ class DatabaseCommand implements Executable * @param array $options Options for command execution * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $command, array $options = []) + public function __construct(string $databaseName, $command, array $options = []) { if (! is_array($command) && ! is_object($command)) { throw InvalidArgumentException::invalidType('$command', $command, 'array or object'); @@ -83,7 +83,7 @@ public function __construct($databaseName, $command, array $options = []) throw InvalidArgumentException::invalidType('"typeMap" option', $options['typeMap'], 'array'); } - $this->databaseName = (string) $databaseName; + $this->databaseName = $databaseName; $this->command = $command instanceof Command ? $command : new Command($command); $this->options = $options; } @@ -92,7 +92,6 @@ public function __construct($databaseName, $command, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return Cursor */ public function execute(Server $server) @@ -110,9 +109,8 @@ public function execute(Server $server) * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php index 95df96624..7ca197f7a 100644 --- a/src/Operation/Delete.php +++ b/src/Operation/Delete.php @@ -97,7 +97,7 @@ class Delete implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $limit, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, int $limit, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -131,8 +131,8 @@ public function __construct($databaseName, $collectionName, $filter, $limit, arr unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->filter = $filter; $this->limit = $limit; $this->options = $options; @@ -142,7 +142,6 @@ public function __construct($databaseName, $collectionName, $filter, $limit, arr * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return DeleteResult * @throws UnsupportedException if hint or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -175,7 +174,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -214,10 +212,8 @@ private function createBulkWriteOptions(): array * * Note that these options are different from the bulk write options, which * are created in createExecuteOptions(). - * - * @return array */ - private function createDeleteOptions() + private function createDeleteOptions(): array { $deleteOptions = ['limit' => $this->limit]; @@ -236,9 +232,8 @@ private function createDeleteOptions() * Create options for executing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php - * @return array */ - private function createExecuteOptions() + private function createExecuteOptions(): array { $options = []; diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php index 3e3a73d0f..33497f3f4 100644 --- a/src/Operation/DeleteMany.php +++ b/src/Operation/DeleteMany.php @@ -68,7 +68,7 @@ class DeleteMany implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { $this->delete = new Delete($databaseName, $collectionName, $filter, 0, $options); } @@ -77,7 +77,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return DeleteResult * @throws UnsupportedException if collation is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -91,7 +90,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php index dda930208..a91d67bb5 100644 --- a/src/Operation/DeleteOne.php +++ b/src/Operation/DeleteOne.php @@ -68,7 +68,7 @@ class DeleteOne implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { $this->delete = new Delete($databaseName, $collectionName, $filter, 1, $options); } @@ -77,7 +77,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return DeleteResult * @throws UnsupportedException if collation is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -91,7 +90,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index 3298cda89..d957bfc29 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -86,7 +86,7 @@ class Distinct implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $fieldName, $filter = [], array $options = []) + public function __construct(string $databaseName, string $collectionName, string $fieldName, $filter = [], array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -120,9 +120,9 @@ public function __construct($databaseName, $collectionName, $fieldName, $filter unset($options['readConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; - $this->fieldName = (string) $fieldName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; + $this->fieldName = $fieldName; $this->filter = $filter; $this->options = $options; } @@ -131,8 +131,7 @@ public function __construct($databaseName, $collectionName, $fieldName, $filter * Execute the operation. * * @see Executable::execute() - * @param Server $server - * @return mixed[] + * @return array * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if read concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -163,7 +162,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -173,10 +171,8 @@ public function getCommandDocument(Server $server) /** * Create the distinct command document. - * - * @return array */ - private function createCommandDocument() + private function createCommandDocument(): array { $cmd = [ 'distinct' => $this->collectionName, @@ -204,9 +200,8 @@ private function createCommandDocument() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 2ab9b8716..846dca4a7 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -71,7 +71,7 @@ class DropCollection implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $options = []) { if (isset($options['session']) && ! $options['session'] instanceof Session) { throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); @@ -89,8 +89,8 @@ public function __construct($databaseName, $collectionName, array $options = []) unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->options = $options; } @@ -98,7 +98,6 @@ public function __construct($databaseName, $collectionName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object Command result document * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -132,10 +131,8 @@ public function execute(Server $server) /** * Create the drop command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = ['drop' => $this->collectionName]; @@ -150,9 +147,8 @@ private function createCommand() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php index 0e569f068..c909b2436 100644 --- a/src/Operation/DropDatabase.php +++ b/src/Operation/DropDatabase.php @@ -63,7 +63,7 @@ class DropDatabase implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, array $options = []) + public function __construct(string $databaseName, array $options = []) { if (isset($options['session']) && ! $options['session'] instanceof Session) { throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); @@ -81,7 +81,7 @@ public function __construct($databaseName, array $options = []) unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; + $this->databaseName = $databaseName; $this->options = $options; } @@ -89,7 +89,6 @@ public function __construct($databaseName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object Command result document * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ @@ -106,10 +105,8 @@ public function execute(Server $server) /** * Create the dropDatabase command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = ['dropDatabase' => 1]; @@ -124,9 +121,8 @@ private function createCommand() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php index e63be7fd1..ef0e2f4d3 100644 --- a/src/Operation/DropIndexes.php +++ b/src/Operation/DropIndexes.php @@ -75,9 +75,9 @@ class DropIndexes implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $indexName, array $options = []) + public function __construct(string $databaseName, string $collectionName, string $indexName, array $options = []) { - $indexName = (string) $indexName; + $indexName = $indexName; if ($indexName === '') { throw new InvalidArgumentException('$indexName cannot be empty'); @@ -103,8 +103,8 @@ public function __construct($databaseName, $collectionName, $indexName, array $o unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->indexName = $indexName; $this->options = $options; } @@ -113,7 +113,6 @@ public function __construct($databaseName, $collectionName, $indexName, array $o * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object Command result document * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -136,10 +135,8 @@ public function execute(Server $server) /** * Create the dropIndexes command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = [ 'dropIndexes' => $this->collectionName, @@ -159,9 +156,8 @@ private function createCommand() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php index 5ed9c73b9..6deeef3e5 100644 --- a/src/Operation/EstimatedDocumentCount.php +++ b/src/Operation/EstimatedDocumentCount.php @@ -77,10 +77,10 @@ class EstimatedDocumentCount implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $options = []) { - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); @@ -105,7 +105,6 @@ public function __construct($databaseName, $collectionName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return integer * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if collation or read concern is used and unsupported @@ -120,7 +119,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/Executable.php b/src/Operation/Executable.php index b71b20ba6..5bd8c68b3 100644 --- a/src/Operation/Executable.php +++ b/src/Operation/Executable.php @@ -32,7 +32,6 @@ interface Executable /** * Execute the operation. * - * @param Server $server * @return mixed */ public function execute(Server $server); diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php index b6cec43e3..13ae85d09 100644 --- a/src/Operation/Explain.php +++ b/src/Operation/Explain.php @@ -78,7 +78,7 @@ class Explain implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, Explainable $explainable, array $options = []) + public function __construct(string $databaseName, Explainable $explainable, array $options = []) { if (isset($options['readPreference']) && ! $options['readPreference'] instanceof ReadPreference) { throw InvalidArgumentException::invalidType('"readPreference" option', $options['readPreference'], ReadPreference::class); @@ -105,7 +105,6 @@ public function __construct($databaseName, Explainable $explainable, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object * @throws UnsupportedException if the server does not support explaining the operation * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -127,11 +126,8 @@ public function execute(Server $server) /** * Create the explain command. - * - * @param Server $server - * @return Command */ - private function createCommand(Server $server) + private function createCommand(Server $server): Command { $cmd = ['explain' => $this->explainable->getCommandDocument($server)]; @@ -148,9 +144,8 @@ private function createCommand(Server $server) * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/Explainable.php b/src/Operation/Explainable.php index 973495235..7647b51ec 100644 --- a/src/Operation/Explainable.php +++ b/src/Operation/Explainable.php @@ -30,7 +30,6 @@ interface Explainable extends Executable /** * Returns the command document for this operation. * - * @param Server $server * @return array */ public function getCommandDocument(Server $server); diff --git a/src/Operation/Find.php b/src/Operation/Find.php index 77e20ba12..619e6f5c5 100644 --- a/src/Operation/Find.php +++ b/src/Operation/Find.php @@ -160,7 +160,7 @@ class Find implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -292,8 +292,8 @@ public function __construct($databaseName, $collectionName, $filter, array $opti trigger_error('The "maxScan" option is deprecated and will be removed in a future release', E_USER_DEPRECATED); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->filter = $filter; $this->options = $options; } @@ -302,7 +302,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return Cursor * @throws UnsupportedException if read concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -327,7 +326,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -380,9 +378,8 @@ private function createCommandDocument(): array * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executequery.php - * @return array */ - private function createExecuteOptions() + private function createExecuteOptions(): array { $options = []; @@ -402,10 +399,8 @@ private function createExecuteOptions() * * Note that these are separate from the options for executing the command, * which are created in createExecuteOptions(). - * - * @return array */ - private function createQueryOptions() + private function createQueryOptions(): array { $options = []; diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index 290b8205f..c5103a8a0 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -129,7 +129,7 @@ class FindAndModify implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $options) + public function __construct(string $databaseName, string $collectionName, array $options) { $options += ['remove' => false]; @@ -209,8 +209,8 @@ public function __construct($databaseName, $collectionName, array $options) unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->options = $options; } @@ -218,7 +218,6 @@ public function __construct($databaseName, $collectionName, array $options) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object|null * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if hint or write concern is used and unsupported @@ -261,7 +260,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -271,10 +269,8 @@ public function getCommandDocument(Server $server) /** * Create the findAndModify command document. - * - * @return array */ - private function createCommandDocument() + private function createCommandDocument(): array { $cmd = ['findAndModify' => $this->collectionName]; @@ -315,9 +311,8 @@ private function createCommandDocument() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php index b75edcb1e..3de70dae6 100644 --- a/src/Operation/FindOne.php +++ b/src/Operation/FindOne.php @@ -103,7 +103,7 @@ class FindOne implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { $this->find = new Find( $databaseName, @@ -117,7 +117,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object|null * @throws UnsupportedException if collation or read concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -134,7 +133,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php index 03fd6e1a7..c4b54dadf 100644 --- a/src/Operation/FindOneAndDelete.php +++ b/src/Operation/FindOneAndDelete.php @@ -81,7 +81,7 @@ class FindOneAndDelete implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -108,7 +108,6 @@ public function __construct($databaseName, $collectionName, $filter, array $opti * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object|null * @throws UnsupportedException if collation or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -122,7 +121,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php index dce8a6a97..0e619b86d 100644 --- a/src/Operation/FindOneAndReplace.php +++ b/src/Operation/FindOneAndReplace.php @@ -100,7 +100,7 @@ class FindOneAndReplace implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, $replacement, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -151,7 +151,6 @@ public function __construct($databaseName, $collectionName, $filter, $replacemen * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object|null * @throws UnsupportedException if collation or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -165,7 +164,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php index 98b6cf42c..e9a592473 100644 --- a/src/Operation/FindOneAndUpdate.php +++ b/src/Operation/FindOneAndUpdate.php @@ -104,7 +104,7 @@ class FindOneAndUpdate implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $update, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, $update, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -155,7 +155,6 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object|null * @throws UnsupportedException if collation or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -169,7 +168,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php index af7bd7361..b8b3c1255 100644 --- a/src/Operation/InsertMany.php +++ b/src/Operation/InsertMany.php @@ -79,7 +79,7 @@ class InsertMany implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $documents, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $documents, array $options = []) { if (empty($documents)) { throw new InvalidArgumentException('$documents is empty'); @@ -125,8 +125,8 @@ public function __construct($databaseName, $collectionName, array $documents, ar unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->documents = $documents; $this->options = $options; } @@ -135,7 +135,6 @@ public function __construct($databaseName, $collectionName, array $documents, ar * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return InsertManyResult * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -163,9 +162,8 @@ public function execute(Server $server) * Create options for constructing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php - * @return array */ - private function createBulkWriteOptions() + private function createBulkWriteOptions(): array { $options = ['ordered' => $this->options['ordered']]; @@ -182,9 +180,8 @@ private function createBulkWriteOptions() * Create options for executing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php - * @return array */ - private function createExecuteOptions() + private function createExecuteOptions(): array { $options = []; diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php index 9398f1795..d0690a5d5 100644 --- a/src/Operation/InsertOne.php +++ b/src/Operation/InsertOne.php @@ -73,7 +73,7 @@ class InsertOne implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $document, array $options = []) + public function __construct(string $databaseName, string $collectionName, $document, array $options = []) { if (! is_array($document) && ! is_object($document)) { throw InvalidArgumentException::invalidType('$document', $document, 'array or object'); @@ -99,8 +99,8 @@ public function __construct($databaseName, $collectionName, $document, array $op unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->document = $document; $this->options = $options; } @@ -109,7 +109,6 @@ public function __construct($databaseName, $collectionName, $document, array $op * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return InsertOneResult * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -133,9 +132,8 @@ public function execute(Server $server) * Create options for constructing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php - * @return array */ - private function createBulkWriteOptions() + private function createBulkWriteOptions(): array { $options = []; @@ -152,9 +150,8 @@ private function createBulkWriteOptions() * Create options for executing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php - * @return array */ - private function createExecuteOptions() + private function createExecuteOptions(): array { $options = []; diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php index 4bc5565a3..d0700887b 100644 --- a/src/Operation/ListCollectionNames.php +++ b/src/Operation/ListCollectionNames.php @@ -61,7 +61,7 @@ class ListCollectionNames implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, array $options = []) + public function __construct(string $databaseName, array $options = []) { $this->listCollections = new ListCollectionsCommand($databaseName, ['nameOnly' => true] + $options); } @@ -70,7 +70,6 @@ public function __construct($databaseName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return Iterator * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php index 8a55f9908..e5702509b 100644 --- a/src/Operation/ListCollections.php +++ b/src/Operation/ListCollections.php @@ -64,9 +64,9 @@ class ListCollections implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, array $options = []) + public function __construct(string $databaseName, array $options = []) { - $this->databaseName = (string) $databaseName; + $this->databaseName = $databaseName; $this->listCollections = new ListCollectionsCommand($databaseName, ['nameOnly' => false] + $options); } @@ -74,7 +74,6 @@ public function __construct($databaseName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return CollectionInfoIterator * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php index 950c82b7c..ccace38f8 100644 --- a/src/Operation/ListDatabaseNames.php +++ b/src/Operation/ListDatabaseNames.php @@ -72,8 +72,6 @@ public function __construct(array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server - * @return Iterator * @throws UnexpectedValueException if the command response was malformed * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ diff --git a/src/Operation/ListDatabases.php b/src/Operation/ListDatabases.php index 6b0c4ba2c..a19cf07bb 100644 --- a/src/Operation/ListDatabases.php +++ b/src/Operation/ListDatabases.php @@ -70,7 +70,6 @@ public function __construct(array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return DatabaseInfoIterator * @throws UnexpectedValueException if the command response was malformed * @throws DriverRuntimeException for other driver errors (e.g. connection errors) diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php index b6e8a1ea0..e762d9ca2 100644 --- a/src/Operation/ListIndexes.php +++ b/src/Operation/ListIndexes.php @@ -73,7 +73,7 @@ class ListIndexes implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $options = []) { if (isset($options['maxTimeMS']) && ! is_integer($options['maxTimeMS'])) { throw InvalidArgumentException::invalidType('"maxTimeMS" option', $options['maxTimeMS'], 'integer'); @@ -83,8 +83,8 @@ public function __construct($databaseName, $collectionName, array $options = []) throw InvalidArgumentException::invalidType('"session" option', $options['session'], Session::class); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->options = $options; } @@ -92,7 +92,6 @@ public function __construct($databaseName, $collectionName, array $options = []) * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return IndexInfoIterator * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ @@ -108,9 +107,8 @@ public function execute(Server $server) * the command be executed on the primary. * * @see https://php.net/manual/en/mongodb-driver-server.executecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; @@ -125,11 +123,9 @@ private function createOptions() * Returns information for all indexes for this collection using the * listIndexes command. * - * @param Server $server - * @return IndexInfoIteratorIterator * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - private function executeCommand(Server $server) + private function executeCommand(Server $server): IndexInfoIteratorIterator { $cmd = ['listIndexes' => $this->collectionName]; diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index b1e8319ce..97e22f080 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -158,7 +158,7 @@ class MapReduce implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = []) + public function __construct(string $databaseName, string $collectionName, JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = []) { if (! is_string($out) && ! is_array($out) && ! is_object($out)) { throw InvalidArgumentException::invalidType('$out', $out, 'string or array or object'); @@ -251,8 +251,8 @@ public function __construct($databaseName, $collectionName, JavascriptInterface $this->checkOutDeprecations($out); - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->map = $map; $this->reduce = $reduce; $this->out = $out; @@ -263,7 +263,6 @@ public function __construct($databaseName, $collectionName, JavascriptInterface * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return MapReduceResult * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if read concern or write concern is used and unsupported @@ -310,9 +309,8 @@ public function execute(Server $server) /** * @param string|array|object $out - * @return void */ - private function checkOutDeprecations($out) + private function checkOutDeprecations($out): void { if (is_string($out)) { return; @@ -331,10 +329,8 @@ private function checkOutDeprecations($out) /** * Create the mapReduce command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = [ 'mapReduce' => $this->collectionName, @@ -361,12 +357,9 @@ private function createCommand() /** * Creates a callable for MapReduceResult::getIterator(). * - * @param stdClass $result - * @param Server $server - * @return callable * @throws UnexpectedValueException if the command response was malformed */ - private function createGetIteratorCallable(stdClass $result, Server $server) + private function createGetIteratorCallable(stdClass $result, Server $server): callable { // Inline results can be wrapped with an ArrayIterator if (isset($result->results) && is_array($result->results)) { @@ -397,10 +390,8 @@ private function createGetIteratorCallable(stdClass $result, Server $server) * * @see https://php.net/manual/en/mongodb-driver-server.executereadcommand.php * @see https://php.net/manual/en/mongodb-driver-server.executereadwritecommand.php - * @param boolean $hasOutputCollection - * @return array */ - private function createOptions($hasOutputCollection) + private function createOptions(bool $hasOutputCollection): array { $options = []; diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php index cd52cb9a0..7933859bf 100644 --- a/src/Operation/ModifyCollection.php +++ b/src/Operation/ModifyCollection.php @@ -70,7 +70,7 @@ class ModifyCollection implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, array $collectionOptions, array $options = []) + public function __construct(string $databaseName, string $collectionName, array $collectionOptions, array $options = []) { if (empty($collectionOptions)) { throw new InvalidArgumentException('$collectionOptions is empty'); @@ -92,8 +92,8 @@ public function __construct($databaseName, $collectionName, array $collectionOpt unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->collectionOptions = $collectionOptions; $this->options = $options; } @@ -102,7 +102,6 @@ public function __construct($databaseName, $collectionName, array $collectionOpt * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object Command result document * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ @@ -132,9 +131,8 @@ private function createCommand(): Command * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php index e489713a3..815428132 100644 --- a/src/Operation/RenameCollection.php +++ b/src/Operation/RenameCollection.php @@ -104,7 +104,6 @@ public function __construct(string $fromDatabaseName, string $fromCollectionName * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return array|object Command result document * @throws UnsupportedException if write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -127,10 +126,8 @@ public function execute(Server $server) /** * Create the renameCollection command. - * - * @return Command */ - private function createCommand() + private function createCommand(): Command { $cmd = [ 'renameCollection' => $this->fromNamespace, @@ -150,9 +147,8 @@ private function createCommand() * Create options for executing the command. * * @see https://php.net/manual/en/mongodb-driver-server.executewritecommand.php - * @return array */ - private function createOptions() + private function createOptions(): array { $options = []; diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php index ef7575ddc..d5d117b91 100644 --- a/src/Operation/ReplaceOne.php +++ b/src/Operation/ReplaceOne.php @@ -80,7 +80,7 @@ class ReplaceOne implements Executable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $replacement, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, $replacement, array $options = []) { if (! is_array($replacement) && ! is_object($replacement)) { throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object'); @@ -107,7 +107,6 @@ public function __construct($databaseName, $collectionName, $filter, $replacemen * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return UpdateResult * @throws UnsupportedException if collation is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) diff --git a/src/Operation/Update.php b/src/Operation/Update.php index 6ec9a2ac5..96a51c53f 100644 --- a/src/Operation/Update.php +++ b/src/Operation/Update.php @@ -112,7 +112,7 @@ class Update implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $update, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, $update, array $options = []) { if (! is_array($filter) && ! is_object($filter)) { throw InvalidArgumentException::invalidType('$filter', $filter, 'array or object'); @@ -175,8 +175,8 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar unset($options['writeConcern']); } - $this->databaseName = (string) $databaseName; - $this->collectionName = (string) $collectionName; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->filter = $filter; $this->update = $update; $this->options = $options; @@ -186,7 +186,6 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return UpdateResult * @throws UnsupportedException if hint or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -219,7 +218,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) @@ -241,9 +239,8 @@ public function getCommandDocument(Server $server) * Create options for constructing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-bulkwrite.construct.php - * @return array */ - private function createBulkWriteOptions() + private function createBulkWriteOptions(): array { $options = []; @@ -264,9 +261,8 @@ private function createBulkWriteOptions() * Create options for executing the bulk write. * * @see https://php.net/manual/en/mongodb-driver-server.executebulkwrite.php - * @return array */ - private function createExecuteOptions() + private function createExecuteOptions(): array { $options = []; @@ -286,10 +282,8 @@ private function createExecuteOptions() * * Note that these options are different from the bulk write options, which * are created in createExecuteOptions(). - * - * @return array */ - private function createUpdateOptions() + private function createUpdateOptions(): array { $updateOptions = [ 'multi' => $this->options['multi'], diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php index 27a6955ad..e442365a1 100644 --- a/src/Operation/UpdateMany.php +++ b/src/Operation/UpdateMany.php @@ -83,7 +83,7 @@ class UpdateMany implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $update, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, $update, array $options = []) { if (! is_array($update) && ! is_object($update)) { throw InvalidArgumentException::invalidType('$update', $update, 'array or object'); @@ -106,7 +106,6 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return UpdateResult * @throws UnsupportedException if collation is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -120,7 +119,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php index 22a01e2a0..a7bfab518 100644 --- a/src/Operation/UpdateOne.php +++ b/src/Operation/UpdateOne.php @@ -83,7 +83,7 @@ class UpdateOne implements Executable, Explainable * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct($databaseName, $collectionName, $filter, $update, array $options = []) + public function __construct(string $databaseName, string $collectionName, $filter, $update, array $options = []) { if (! is_array($update) && ! is_object($update)) { throw InvalidArgumentException::invalidType('$update', $update, 'array or object'); @@ -106,7 +106,6 @@ public function __construct($databaseName, $collectionName, $filter, $update, ar * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return UpdateResult * @throws UnsupportedException if collation is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -120,7 +119,6 @@ public function execute(Server $server) * Returns the command document for this operation. * * @see Explainable::getCommandDocument() - * @param Server $server * @return array */ public function getCommandDocument(Server $server) diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index 3daf2d26a..a188ba774 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -201,7 +201,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber * @param array $options Command options * @throws InvalidArgumentException for parameter/option parsing errors */ - public function __construct(Manager $manager, $databaseName, $collectionName, array $pipeline, array $options = []) + public function __construct(Manager $manager, ?string $databaseName, ?string $collectionName, array $pipeline, array $options = []) { if (isset($collectionName) && ! isset($databaseName)) { throw new InvalidArgumentException('$collectionName should also be null if $databaseName is null'); @@ -263,8 +263,8 @@ public function __construct(Manager $manager, $databaseName, $collectionName, ar } $this->manager = $manager; - $this->databaseName = (string) $databaseName; - $this->collectionName = isset($collectionName) ? (string) $collectionName : null; + $this->databaseName = $databaseName; + $this->collectionName = $collectionName; $this->pipeline = $pipeline; $this->aggregate = $this->createAggregate(); @@ -317,7 +317,6 @@ final public function commandSucceeded(CommandSucceededEvent $event): void * Execute the operation. * * @see Executable::execute() - * @param Server $server * @return ChangeStream * @throws UnsupportedException if collation or read concern is used and unsupported * @throws RuntimeException for other driver errors (e.g. connection errors) @@ -336,10 +335,8 @@ function ($resumeToken, $hasAdvanced) { * Create the aggregate command for a change stream. * * This method is also used to recreate the aggregate command when resuming. - * - * @return Aggregate */ - private function createAggregate() + private function createAggregate(): Aggregate { $pipeline = $this->pipeline; array_unshift($pipeline, ['$changeStream' => (object) $this->changeStreamOptions]); @@ -349,11 +346,8 @@ private function createAggregate() /** * Create a ChangeStreamIterator by executing the aggregate command. - * - * @param Server $server - * @return ChangeStreamIterator */ - private function createChangeStreamIterator(Server $server) + private function createChangeStreamIterator(Server $server): ChangeStreamIterator { return new ChangeStreamIterator( $this->executeAggregate($server), @@ -368,11 +362,8 @@ private function createChangeStreamIterator(Server $server) * * The command will be executed using APM so that we can capture data from * its response (e.g. firstBatch size, postBatchResumeToken). - * - * @param Server $server - * @return Cursor */ - private function executeAggregate(Server $server) + private function executeAggregate(Server $server): Cursor { addSubscriber($this); @@ -411,11 +402,9 @@ private function getInitialResumeToken() * * @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#resume-process * @param array|object|null $resumeToken - * @param bool $hasAdvanced - * @return ChangeStreamIterator * @throws InvalidArgumentException */ - private function resume($resumeToken = null, $hasAdvanced = false) + private function resume($resumeToken = null, bool $hasAdvanced = false): ChangeStreamIterator { if (isset($resumeToken) && ! is_array($resumeToken) && ! is_object($resumeToken)) { throw InvalidArgumentException::invalidType('$resumeToken', $resumeToken, 'array or object'); @@ -453,10 +442,8 @@ private function resume($resumeToken = null, $hasAdvanced = false) * Determine whether to capture operation time from an aggregate response. * * @see https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst#startatoperationtime - * @param Server $server - * @return boolean */ - private function shouldCaptureOperationTime(Server $server) + private function shouldCaptureOperationTime(Server $server): bool { if ($this->hasResumed) { return false; diff --git a/src/Operation/WithTransaction.php b/src/Operation/WithTransaction.php index 6278972dd..e31b01b9e 100644 --- a/src/Operation/WithTransaction.php +++ b/src/Operation/WithTransaction.php @@ -52,11 +52,10 @@ public function __construct(callable $callback, array $transactionOptions = []) * @see Client::startSession * * @param Session $session A session object as retrieved by Client::startSession - * @return void * @throws RuntimeException for driver errors while committing the transaction * @throws Exception for any other errors, including those thrown in the callback */ - public function execute(Session $session) + public function execute(Session $session): void { $startTime = time(); @@ -123,9 +122,8 @@ public function execute(Session $session) * Returns whether the time limit for retrying transactions in the convenient transaction API has passed * * @param int $startTime The time the transaction was started - * @return bool */ - private function isTransactionTimeLimitExceeded($startTime) + private function isTransactionTimeLimitExceeded(int $startTime): bool { return time() - $startTime >= 120; } diff --git a/src/functions.php b/src/functions.php index c0ab80e9a..042bee19f 100644 --- a/src/functions.php +++ b/src/functions.php @@ -98,7 +98,6 @@ function apply_type_map_to_document($document, array $typeMap) * @internal * @param array|object $document Document containing fields mapped to values, * which denote order or an index type - * @return string * @throws InvalidArgumentException */ function generate_index_name($document): string @@ -178,7 +177,6 @@ function get_encrypted_fields_from_server(string $databaseName, string $collecti * * @internal * @param array|object $document Update or replacement document - * @return boolean * @throws InvalidArgumentException */ function is_first_key_operator($document): bool @@ -206,7 +204,6 @@ function is_first_key_operator($document): bool * * @internal * @param mixed $pipeline - * @return boolean */ function is_pipeline($pipeline): bool { @@ -247,7 +244,6 @@ function is_pipeline($pipeline): bool * * @internal * @param array $options Command options - * @return boolean */ function is_in_transaction(array $options): bool { @@ -266,7 +262,6 @@ function is_in_transaction(array $options): bool * * @internal * @param array $pipeline List of pipeline operations - * @return boolean */ function is_last_pipeline_operator_write(array $pipeline): bool { @@ -289,7 +284,6 @@ function is_last_pipeline_operator_write(array $pipeline): bool * @internal * @see https://mongodb.com/docs/manual/reference/command/mapReduce/#output-inline * @param string|array|object $out Output specification - * @return boolean * @throws InvalidArgumentException */ function is_mapreduce_output_inline($out): bool @@ -323,8 +317,6 @@ function is_mapreduce_output_inline($out): bool * * @internal * @see https://mongodb.com/docs/manual/reference/write-concern/ - * @param WriteConcern $writeConcern - * @return boolean */ function is_write_concern_acknowledged(WriteConcern $writeConcern): bool { @@ -340,7 +332,6 @@ function is_write_concern_acknowledged(WriteConcern $writeConcern): bool * @internal * @param Server $server Server to check * @param integer $feature Feature constant (i.e. wire protocol version) - * @return boolean */ function server_supports_feature(Server $server, int $feature): bool { @@ -356,7 +347,6 @@ function server_supports_feature(Server $server, int $feature): bool * * @internal * @param mixed $input - * @return boolean */ function is_string_array($input): bool { @@ -417,7 +407,6 @@ function recursive_copy($element) * @internal * @param array $typeMap The existing typeMap * @param string $fieldPath The field path to apply the root type to - * @return array */ function create_field_path_type_map(array $typeMap, string $fieldPath): array { @@ -470,11 +459,10 @@ function create_field_path_type_map(array $typeMap, string $fieldPath): array * @param Session $session A session object as retrieved by Client::startSession * @param callable $callback A callback that will be invoked within the transaction * @param array $transactionOptions Additional options that are passed to Session::startTransaction - * @return void * @throws RuntimeException for driver errors while committing the transaction * @throws Exception for any other errors, including those thrown in the callback */ -function with_transaction(Session $session, callable $callback, array $transactionOptions = []) +function with_transaction(Session $session, callable $callback, array $transactionOptions = []): void { $operation = new WithTransaction($callback, $transactionOptions); $operation->execute($session); @@ -484,8 +472,6 @@ function with_transaction(Session $session, callable $callback, array $transacti * Returns the session option if it is set and valid. * * @internal - * @param array $options - * @return Session|null */ function extract_session_from_options(array $options): ?Session { @@ -500,8 +486,6 @@ function extract_session_from_options(array $options): ?Session * Returns the readPreference option if it is set and valid. * * @internal - * @param array $options - * @return ReadPreference|null */ function extract_read_preference_from_options(array $options): ?ReadPreference { @@ -517,7 +501,6 @@ function extract_read_preference_from_options(array $options): ?ReadPreference * (if given) * * @internal - * @return Server */ function select_server(Manager $manager, array $options): Server { diff --git a/tests/ClientFunctionalTest.php b/tests/ClientFunctionalTest.php index a51b90d60..6535c66da 100644 --- a/tests/ClientFunctionalTest.php +++ b/tests/ClientFunctionalTest.php @@ -91,9 +91,6 @@ public function testListDatabaseNames(): void * argument as its first and only parameter. If a DatabaseInfo matching * the given name is found, it will be passed to the callback, which may * perform additional assertions. - * - * @param string $databaseName - * @param callable $callback */ private function assertDatabaseExists(string $databaseName, ?callable $callback = null): void { diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php index e1e9fc982..cd687bc0e 100644 --- a/tests/Collection/CollectionFunctionalTest.php +++ b/tests/Collection/CollectionFunctionalTest.php @@ -15,6 +15,7 @@ use MongoDB\MapReduceResult; use MongoDB\Operation\Count; use MongoDB\Tests\CommandObserver; +use TypeError; use function array_filter; use function call_user_func; @@ -32,9 +33,9 @@ class CollectionFunctionalTest extends FunctionalTestCase /** * @dataProvider provideInvalidDatabaseAndCollectionNames */ - public function testConstructorDatabaseNameArgument($databaseName): void + public function testConstructorDatabaseNameArgument($databaseName, string $expectedExceptionClass): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException($expectedExceptionClass); // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) new Collection($this->manager, $databaseName, $this->getCollectionName()); } @@ -42,9 +43,9 @@ public function testConstructorDatabaseNameArgument($databaseName): void /** * @dataProvider provideInvalidDatabaseAndCollectionNames */ - public function testConstructorCollectionNameArgument($collectionName): void + public function testConstructorCollectionNameArgument($collectionName, string $expectedExceptionClass): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException($expectedExceptionClass); // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) new Collection($this->manager, $this->getDatabaseName(), $collectionName); } @@ -52,8 +53,8 @@ public function testConstructorCollectionNameArgument($collectionName): void public function provideInvalidDatabaseAndCollectionNames() { return [ - [null], - [''], + [null, TypeError::class], + ['', InvalidArgumentException::class], ]; } @@ -805,9 +806,6 @@ public function testMethodInTransactionWithReadConcernOption($method): void /** * Create data fixtures. - * - * @param integer $n - * @param array $executeBulkWriteOptions */ private function createFixtures(int $n, array $executeBulkWriteOptions = []): void { diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php index f1cc519b6..4bb7ac174 100644 --- a/tests/Collection/CrudSpecFunctionalTest.php +++ b/tests/Collection/CrudSpecFunctionalTest.php @@ -107,9 +107,6 @@ public function provideSpecificationTests() /** * Assert that the collections contain equivalent documents. - * - * @param Collection $expectedCollection - * @param Collection $actualCollection */ private function assertEquivalentCollections(Collection $expectedCollection, Collection $actualCollection): void { @@ -152,8 +149,6 @@ private function checkServerlessRequirement(?string $serverless): void /** * Checks that the server version is within the allowed bounds (if any). * - * @param string|null $minServerVersion - * @param string|null $maxServerVersion * @throws PHPUnit_Framework_SkippedTestError */ private function checkServerVersion(?string $minServerVersion, ?string $maxServerVersion): void @@ -172,7 +167,6 @@ private function checkServerVersion(?string $minServerVersion, ?string $maxServe /** * Executes an "operation" block. * - * @param array $operation * @return mixed * @throws LogicException if the operation is unsupported */ @@ -260,10 +254,7 @@ private function executeOperation(array $operation) /** * Executes an "outcome" block. * - * @param array $operation - * @param array $outcome - * @param mixed $result - * @param RuntimeException $exception + * @param mixed $result * @return mixed * @throws LogicException if the operation is unsupported */ @@ -300,8 +291,6 @@ private function executeOutcome(array $operation, array $outcome, $result, ?Runt * * If no result can be extracted, null will be returned. * - * @param array $operation - * @param RuntimeException $exception * @return mixed */ private function extractResultFromException(array $operation, array $outcome, RuntimeException $exception) @@ -332,7 +321,6 @@ private function extractResultFromException(array $operation, array $outcome, Ru /** * Executes the "result" section of an "outcome" block. * - * @param array $operation * @param mixed $expectedResult * @param mixed $actualResult * @throws LogicException if the operation is unsupported @@ -498,9 +486,6 @@ private function executeAssertResult(array $operation, $expectedResult, $actualR /** * Initializes data in the test collections. - * - * @param array $initialData - * @param array $expectedData */ private function initializeData(array $initialData, ?array $expectedData = null): void { @@ -515,9 +500,6 @@ private function initializeData(array $initialData, ?array $expectedData = null) /** * Prepares a request element for a bulkWrite operation. - * - * @param array $request - * @return array */ private function prepareBulkWriteRequest(array $request): array { @@ -560,9 +542,6 @@ private function prepareBulkWriteRequest(array $request): array /** * Prepares arguments for findOneAndReplace and findOneAndUpdate operations. - * - * @param array $arguments - * @return array */ private function prepareFindAndModifyArguments(array $arguments): array { diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php index 180762384..6eb2f9fd1 100644 --- a/tests/Database/DatabaseFunctionalTest.php +++ b/tests/Database/DatabaseFunctionalTest.php @@ -11,6 +11,7 @@ use MongoDB\Driver\WriteConcern; use MongoDB\Exception\InvalidArgumentException; use MongoDB\Operation\CreateIndexes; +use TypeError; use function array_key_exists; use function current; @@ -23,9 +24,9 @@ class DatabaseFunctionalTest extends FunctionalTestCase /** * @dataProvider provideInvalidDatabaseNames */ - public function testConstructorDatabaseNameArgument($databaseName): void + public function testConstructorDatabaseNameArgument($databaseName, string $expectedExceptionClass): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException($expectedExceptionClass); // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378) new Database($this->manager, $databaseName); } @@ -33,8 +34,8 @@ public function testConstructorDatabaseNameArgument($databaseName): void public function provideInvalidDatabaseNames() { return [ - [null], - [''], + [null, TypeError::class], + ['', InvalidArgumentException::class], ]; } diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php index 23ac8b50f..d766ed8ea 100644 --- a/tests/DocumentationExamplesTest.php +++ b/tests/DocumentationExamplesTest.php @@ -1958,8 +1958,6 @@ public function testQueryableEncryption(): void /** * Return the test collection name. - * - * @return string */ protected function getCollectionName(): string { diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 60cf9ff3a..76d81fb4e 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -305,8 +305,6 @@ public static function getModuleInfo(string $row): ?string * If the "writeConcern" option is not specified but is supported by the * server, a majority write concern will be used. This is helpful for tests * using transactions or secondary reads. - * - * @param array $options */ protected function createCollection(array $options = []): void { @@ -322,8 +320,6 @@ protected function createCollection(array $options = []): void * If the "writeConcern" option is not specified but is supported by the * server, a majority write concern will be used. This is helpful for tests * using transactions or secondary reads. - * - * @param array $options */ protected function dropCollection(array $options = []): void { @@ -615,8 +611,6 @@ private function disableFailPoints(): void /** * Checks if the failCommand command is supported on this server version - * - * @return bool */ private function isFailCommandSupported(): bool { @@ -627,8 +621,6 @@ private function isFailCommandSupported(): bool /** * Checks if the failCommand command is enabled by checking the enableTestCommands parameter - * - * @return bool */ private function isFailCommandEnabled(): bool { diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index f00e23049..c59f4c128 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -782,10 +782,6 @@ public function testDanglingOpenWritableStream(): void * argument as its first and only parameter. If an IndexInfo matching the * given name is found, it will be passed to the callback, which may perform * additional assertions. - * - * @param string $collectionName - * @param string $indexName - * @param callable $callback */ private function assertIndexExists(string $collectionName, string $indexName, ?callable $callback = null): void { @@ -814,9 +810,6 @@ private function assertIndexExists(string $collectionName, string $indexName, ?c /** * Asserts that an index with the given name does not exist for the collection. - * - * @param string $collectionName - * @param string $indexName */ private function assertIndexNotExists(string $collectionName, string $indexName): void { @@ -837,8 +830,6 @@ private function assertIndexNotExists(string $collectionName, string $indexName) /** * Return a list of invalid stream values. - * - * @return array */ private function getInvalidStreamValues(): array { diff --git a/tests/GridFS/FunctionalTestCase.php b/tests/GridFS/FunctionalTestCase.php index 5c2b8f45e..d78b1e6b1 100644 --- a/tests/GridFS/FunctionalTestCase.php +++ b/tests/GridFS/FunctionalTestCase.php @@ -42,7 +42,6 @@ public function setUp(): void * * Note: this will seek to the beginning of the stream before reading. * - * @param string $expectedContents * @param resource $stream */ protected function assertStreamContents(string $expectedContents, $stream): void @@ -55,7 +54,6 @@ protected function assertStreamContents(string $expectedContents, $stream): void /** * Creates an in-memory stream with the given data. * - * @param string $data * @return resource */ protected function createStream(string $data = '') diff --git a/tests/Model/ChangeStreamIteratorTest.php b/tests/Model/ChangeStreamIteratorTest.php index af3f0bdf6..9be703bab 100644 --- a/tests/Model/ChangeStreamIteratorTest.php +++ b/tests/Model/ChangeStreamIteratorTest.php @@ -1,5 +1,10 @@ expectException(InvalidArgumentException::class); + $this->expectException(TypeError::class); new ChangeStreamIterator($this->collection->find(), $firstBatchSize, null, null); } - public function provideInvalidIntegerValues() - { - return $this->wrapValuesForDataProvider($this->getInvalidIntegerValues()); - } - public function testInitialResumeToken(): void { $iterator = new ChangeStreamIterator($this->collection->find(), 0, null, null); @@ -73,7 +74,7 @@ public function testInitialResumeTokenArgumentTypeCheck($initialResumeToken): vo */ public function testPostBatchResumeTokenArgumentTypeCheck($postBatchResumeToken): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException(TypeError::class); new ChangeStreamIterator($this->collection->find(), 0, null, $postBatchResumeToken); } diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php index d300fd57b..d8b6c13af 100644 --- a/tests/Operation/AggregateFunctionalTest.php +++ b/tests/Operation/AggregateFunctionalTest.php @@ -339,9 +339,6 @@ public function testReadPreferenceWithinTransaction(): void /** * Create data fixtures. - * - * @param integer $n - * @param array $executeBulkWriteOptions */ private function createFixtures(int $n, array $executeBulkWriteOptions = []): void { diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php index dd0a18eaf..b935e5501 100644 --- a/tests/Operation/BulkWriteFunctionalTest.php +++ b/tests/Operation/BulkWriteFunctionalTest.php @@ -313,8 +313,6 @@ public function testBulkWriteWithPipelineUpdates(): void /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/Operation/CreateIndexesFunctionalTest.php b/tests/Operation/CreateIndexesFunctionalTest.php index 8bc79d87a..d3d1b8e63 100644 --- a/tests/Operation/CreateIndexesFunctionalTest.php +++ b/tests/Operation/CreateIndexesFunctionalTest.php @@ -223,9 +223,6 @@ public function testCommitQuorumUnsupported(): void * argument as its first and only parameter. If an IndexInfo matching the * given name is found, it will be passed to the callback, which may perform * additional assertions. - * - * @param string $indexName - * @param callable $callback */ private function assertIndexExists(string $indexName, ?callable $callback = null): void { diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php index 3bfd4c79f..d97d53474 100644 --- a/tests/Operation/DeleteFunctionalTest.php +++ b/tests/Operation/DeleteFunctionalTest.php @@ -129,8 +129,6 @@ public function testUnacknowledgedWriteConcernAccessesDeletedCount(DeleteResult /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/Operation/DeleteTest.php b/tests/Operation/DeleteTest.php index 2bbfda47f..859721f6d 100644 --- a/tests/Operation/DeleteTest.php +++ b/tests/Operation/DeleteTest.php @@ -1,11 +1,15 @@ getDatabaseName(), $this->getCollectionName(), $filter, 0); } + /** + * @dataProvider provideInvalidIntegerValues + */ + public function testConstructorLimitArgumentMustBeInt($limit): void + { + $this->expectException(TypeError::class); + new Delete($this->getDatabaseName(), $this->getCollectionName(), [], $limit); + } + /** * @dataProvider provideInvalidLimitValues */ @@ -30,7 +43,7 @@ public function testConstructorLimitArgumentMustBeOneOrZero($limit): void public function provideInvalidLimitValues() { - return $this->wrapValuesForDataProvider(array_merge($this->getInvalidIntegerValues(), [-1, 2])); + return $this->wrapValuesForDataProvider([-1, 2]); } /** diff --git a/tests/Operation/DropDatabaseFunctionalTest.php b/tests/Operation/DropDatabaseFunctionalTest.php index 2b62c6294..217bf1e63 100644 --- a/tests/Operation/DropDatabaseFunctionalTest.php +++ b/tests/Operation/DropDatabaseFunctionalTest.php @@ -78,9 +78,6 @@ function (array $event): void { /** * Asserts that a database with the given name does not exist on the server. - * - * @param Server $server - * @param string $databaseName */ private function assertDatabaseDoesNotExist(Server $server, string $databaseName): void { diff --git a/tests/Operation/DropIndexesFunctionalTest.php b/tests/Operation/DropIndexesFunctionalTest.php index cc5f75ffa..a7cecf548 100644 --- a/tests/Operation/DropIndexesFunctionalTest.php +++ b/tests/Operation/DropIndexesFunctionalTest.php @@ -149,8 +149,6 @@ function (array $event): void { * argument as its first and only parameter. If an IndexInfo matching the * given name is found, it will be passed to the callback, which may perform * additional assertions. - * - * @param callable $callback */ private function assertIndexExists($indexName, ?callable $callback = null): void { diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php index a639a1d67..fe4f154e7 100644 --- a/tests/Operation/ExplainFunctionalTest.php +++ b/tests/Operation/ExplainFunctionalTest.php @@ -425,8 +425,6 @@ private function assertExplainResult($result, $executionStatsExpected, $allPlans /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index 13f6184fb..b9b6b605c 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -199,8 +199,6 @@ public function provideTypeMapOptionsAndExpectedDocument() /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php index e8996f27a..5ff55752b 100644 --- a/tests/Operation/FindFunctionalTest.php +++ b/tests/Operation/FindFunctionalTest.php @@ -246,9 +246,6 @@ public function testReadPreferenceWithinTransaction(): void /** * Create data fixtures. - * - * @param integer $n - * @param array $executeBulkWriteOptions */ private function createFixtures(int $n, array $executeBulkWriteOptions = []): void { diff --git a/tests/Operation/FindOneFunctionalTest.php b/tests/Operation/FindOneFunctionalTest.php index e15e6967c..cd1096fa7 100644 --- a/tests/Operation/FindOneFunctionalTest.php +++ b/tests/Operation/FindOneFunctionalTest.php @@ -40,8 +40,6 @@ public function provideTypeMapOptionsAndExpectedDocument() /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php index 204be0906..d47109b03 100644 --- a/tests/Operation/MapReduceFunctionalTest.php +++ b/tests/Operation/MapReduceFunctionalTest.php @@ -294,8 +294,6 @@ public function testTypeMapOptionWithOutputCollection(?array $typeMap, array $ex /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php index cf7392584..c0b6ba76a 100644 --- a/tests/Operation/UpdateFunctionalTest.php +++ b/tests/Operation/UpdateFunctionalTest.php @@ -267,8 +267,6 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedId(UpdateResult $r /** * Create data fixtures. - * - * @param integer $n */ private function createFixtures(int $n): void { diff --git a/tests/PHPUnit/Functions.php b/tests/PHPUnit/Functions.php index 6f9bf5dee..55edd3a6f 100644 --- a/tests/PHPUnit/Functions.php +++ b/tests/PHPUnit/Functions.php @@ -1249,13 +1249,11 @@ function assertClassNotHasStaticAttribute(string $attributeName, string $classNa * * @see Assert::assertObjectHasAttribute * - * @param object $object - * * @throws ExpectationFailedException * @throws InvalidArgumentException * @throws Exception */ - function assertObjectHasAttribute(string $attributeName, $object, string $message = ''): void + function assertObjectHasAttribute(string $attributeName, object $object, string $message = ''): void { Assert::assertObjectHasAttribute(...func_get_args()); } @@ -1267,13 +1265,11 @@ function assertObjectHasAttribute(string $attributeName, $object, string $messag * * @see Assert::assertObjectNotHasAttribute * - * @param object $object - * * @throws ExpectationFailedException * @throws InvalidArgumentException * @throws Exception */ - function assertObjectNotHasAttribute(string $attributeName, $object, string $message = ''): void + function assertObjectNotHasAttribute(string $attributeName, object $object, string $message = ''): void { Assert::assertObjectNotHasAttribute(...func_get_args()); } @@ -1952,9 +1948,6 @@ function assertStringStartsWith(string $prefix, string $string, string $message * * @see Assert::assertStringStartsNotWith * - * @param string $prefix - * @param string $string - * * @throws ExpectationFailedException * @throws InvalidArgumentException */ @@ -2222,9 +2215,6 @@ function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJs * * @see Assert::assertJsonStringNotEqualsJsonString * - * @param string $expectedJson - * @param string $actualJson - * * @throws ExpectationFailedException * @throws InvalidArgumentException */ diff --git a/tests/SpecTests/CommandExpectations.php b/tests/SpecTests/CommandExpectations.php index e25ea7c29..86492a3ed 100644 --- a/tests/SpecTests/CommandExpectations.php +++ b/tests/SpecTests/CommandExpectations.php @@ -198,9 +198,6 @@ public function stopMonitoring(): void /** * Assert that the command expectations match the monitored events. - * - * @param FunctionalTestCase $test Test instance - * @param Context $context Execution context */ public function assert(FunctionalTestCase $test, Context $context): void { diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index fbc55ae31..0ead3e961 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -317,8 +317,6 @@ public function getInternalClient(): Client * Prepare options readConcern, readPreference, and writeConcern options by * creating value objects. * - * @param array $options - * @return array * @throws LogicException if any option keys are unsupported */ public function prepareOptions(array $options): array diff --git a/tests/SpecTests/DocumentsMatchConstraint.php b/tests/SpecTests/DocumentsMatchConstraint.php index b512cfd28..9940586c4 100644 --- a/tests/SpecTests/DocumentsMatchConstraint.php +++ b/tests/SpecTests/DocumentsMatchConstraint.php @@ -132,8 +132,7 @@ private function doEvaluate($other, $description = '', $returnResult = false) } /** - * @param string $expectedType - * @param mixed $actualValue + * @param mixed $actualValue */ private function assertBSONType(string $expectedType, $actualValue): void { @@ -275,10 +274,6 @@ private function assertBSONType(string $expectedType, $actualValue): void /** * Compares two documents recursively. * - * @param ArrayObject $expected - * @param ArrayObject $actual - * @param boolean $ignoreExtraKeys - * @param string $keyPrefix * @throws RuntimeException if the documents do not match */ private function assertEquals(ArrayObject $expected, ArrayObject $actual, bool $ignoreExtraKeys, string $keyPrefix = ''): void @@ -412,8 +407,7 @@ private static function isNumeric($value): bool * value within the array or document will then be prepared recursively. * * @param array|object $bson - * @param boolean $isRoot If true, ensure an array value is converted to a document - * @param boolean $sortKeys + * @param boolean $isRoot If true, ensure an array value is converted to a document * @return BSONDocument|BSONArray * @throws InvalidArgumentException if $bson is not an array or object */ diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php index 0606e0356..3b266fb04 100644 --- a/tests/SpecTests/FunctionalTestCase.php +++ b/tests/SpecTests/FunctionalTestCase.php @@ -87,7 +87,6 @@ public static function assertCommandReplyMatches(stdClass $expected, stdClass $a * * @param array|object $expectedDocument * @param array|object $actualDocument - * @param string $message */ public static function assertDocumentsMatch($expectedDocument, $actualDocument, string $message = ''): void { @@ -98,9 +97,6 @@ public static function assertDocumentsMatch($expectedDocument, $actualDocument, /** * Assert data within the outcome collection. - * - * @param array $expectedDocuments - * @param int $resultExpectation */ protected function assertOutcomeCollectionData(array $expectedDocuments, int $resultExpectation = ResultExpectation::ASSERT_SAME_DOCUMENT): void { @@ -133,7 +129,6 @@ protected function assertOutcomeCollectionData(array $expectedDocuments, int $re /** * Checks server version and topology requirements. * - * @param array $runOn * @throws SkippedTest if the server requirements are not met */ protected function checkServerRequirements(array $runOn): void @@ -161,7 +156,6 @@ protected function checkServerRequirements(array $runOn): void * This decodes the file through the driver's extended JSON parser to ensure * proper handling of special types. * - * @param string $json * @return array|object */ protected function decodeJson(string $json) @@ -172,7 +166,6 @@ protected function decodeJson(string $json) /** * Return the test context. * - * @return Context * @throws LogicException if the context has not been set */ protected function getContext(): Context @@ -186,8 +179,6 @@ protected function getContext(): Context /** * Set the test context. - * - * @param Context $context */ protected function setContext(Context $context): void { @@ -228,9 +219,6 @@ protected function dropTestAndOutcomeCollections(array $testCollectionDropOption /** * Insert data fixtures into the test collection. - * - * @param array $documents - * @param string|null $collectionName */ protected function insertDataFixtures(array $documents, ?string $collectionName = null): void { @@ -257,7 +245,6 @@ private function getOutcomeCollection(array $collectionOptions = []) /** * Return the corresponding topology constants for the current topology. * - * @return string * @throws UnexpectedValueException if topology is neither single nor RS nor sharded */ private function getTopology(): string @@ -300,11 +287,6 @@ private function isServerlessRequirementSatisfied(?string $serverlessMode): bool /** * Checks if server version and topology requirements are satifised. - * - * @param string|null $minServerVersion - * @param string|null $maxServerVersion - * @param array|null $topologies - * @return boolean */ private function isServerRequirementSatisifed(?string $minServerVersion, ?string $maxServerVersion, ?array $topologies = null, ?string $serverlessMode = null): bool { diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php index 25f1c07d4..42d9da990 100644 --- a/tests/SpecTests/Operation.php +++ b/tests/SpecTests/Operation.php @@ -100,8 +100,6 @@ public static function fromClientSideEncryption(stdClass $operation) /** * This method is exclusively used to prepare nested operations for the * withTransaction session operation - * - * @return Operation */ private static function fromConvenientTransactions(stdClass $operation): Operation { @@ -189,9 +187,7 @@ public static function fromTransactions(stdClass $operation) /** * Execute the operation and assert its outcome. * - * @param FunctionalTestCase $test Test instance - * @param Context $context Execution context - * @param bool $bubbleExceptions If true, any exception that was caught is rethrown + * @param bool $bubbleExceptions If true, any exception that was caught is rethrown */ public function assert(FunctionalTestCase $test, Context $context, bool $bubbleExceptions = false): void { @@ -237,7 +233,6 @@ public function assert(FunctionalTestCase $test, Context $context, bool $bubbleE /** * Executes the operation with a given context. * - * @param Context $context Execution context * @return mixed * @throws LogicException if the operation is unsupported */ @@ -291,8 +286,6 @@ private function execute(FunctionalTestCase $test, Context $context) /** * Executes the client operation and return its result. * - * @param Client $client - * @param Context $context Execution context * @return mixed * @throws LogicException if the collection operation is unsupported */ @@ -322,8 +315,6 @@ private function executeForClient(Client $client, Context $context) /** * Executes the collection operation and return its result. * - * @param Collection $collection - * @param Context $context Execution context * @return mixed * @throws LogicException if the collection operation is unsupported */ @@ -464,8 +455,6 @@ private function executeForCollection(Collection $collection, Context $context) /** * Executes the database operation and return its result. * - * @param Database $database - * @param Context $context Execution context * @return mixed * @throws LogicException if the database operation is unsupported */ @@ -519,8 +508,6 @@ private function executeForDatabase(Database $database, Context $context) /** * Executes the GridFS bucket operation and return its result. * - * @param Bucket $bucket - * @param Context $context Execution context * @return mixed * @throws LogicException if the database operation is unsupported */ @@ -562,9 +549,6 @@ private function executeForGridFSBucket(Bucket $bucket, Context $context) /** * Executes the session operation and return its result. * - * @param Session $session - * @param FunctionalTestCase $test - * @param Context $context Execution context * @return mixed * @throws LogicException if the session operation is unsupported */ @@ -672,12 +656,6 @@ private function executeForTestRunner(FunctionalTestCase $test, Context $context } } - /** - * @param string $databaseName - * @param string $collectionName - * - * @return array - */ private function getIndexNames(Context $context, string $databaseName, string $collectionName): array { return array_map( @@ -838,8 +816,6 @@ private function getResultAssertionTypeForDatabase() /** * Prepares a request element for a bulkWrite operation. * - * @param stdClass $request - * @return array * @throws LogicException if the bulk write request is unsupported */ private function prepareBulkWriteRequest(stdClass $request): array diff --git a/tests/SpecTests/ResultExpectation.php b/tests/SpecTests/ResultExpectation.php index bb6f1c282..9626719e2 100644 --- a/tests/SpecTests/ResultExpectation.php +++ b/tests/SpecTests/ResultExpectation.php @@ -45,10 +45,6 @@ final class ResultExpectation /** @var callable */ private $assertionCallable; - /** - * @param integer $assertionType - * @param mixed $expectedValue - */ private function __construct(int $assertionType, $expectedValue) { switch ($assertionType) { @@ -352,7 +348,6 @@ private static function isArrayOfObjects($array) * * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#test-format * @param mixed $result - * @return boolean */ private static function isErrorResult($result): bool { diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php index 4f26e9c3e..15f4fefe6 100644 --- a/tests/SpecTests/TransactionsSpecTest.php +++ b/tests/SpecTests/TransactionsSpecTest.php @@ -352,7 +352,6 @@ private static function killAllSessions(): void /** * Work around potential error executing distinct on sharded clusters. * - * @param array $operations * @see https://github.com/mongodb/specifications/tree/master/source/transactions/tests#why-do-tests-that-run-distinct-sometimes-fail-with-staledbversion */ private function preventStaleDbVersionError(array $operations): void diff --git a/tests/TestCase.php b/tests/TestCase.php index 133d9699f..7ed378e11 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -35,8 +35,6 @@ abstract class TestCase extends BaseTestCase { /** * Return the connection URI. - * - * @return string */ public static function getUri(): string { @@ -134,6 +132,11 @@ public function provideInvalidDocumentValues() return $this->wrapValuesForDataProvider($this->getInvalidDocumentValues()); } + public function provideInvalidIntegerValues() + { + return $this->wrapValuesForDataProvider($this->getInvalidIntegerValues()); + } + protected function assertDeprecated(callable $execution): void { $errors = []; @@ -153,8 +156,6 @@ protected function assertDeprecated(callable $execution): void /** * Return the test collection name. - * - * @return string */ protected function getCollectionName(): string { @@ -165,8 +166,6 @@ protected function getCollectionName(): string /** * Return the test database name. - * - * @return string */ protected function getDatabaseName(): string { @@ -175,10 +174,6 @@ protected function getDatabaseName(): string /** * Return a list of invalid array values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidArrayValues(bool $includeNull = false): array { @@ -187,10 +182,6 @@ protected function getInvalidArrayValues(bool $includeNull = false): array /** * Return a list of invalid boolean values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidBooleanValues(bool $includeNull = false): array { @@ -199,10 +190,6 @@ protected function getInvalidBooleanValues(bool $includeNull = false): array /** * Return a list of invalid document values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidDocumentValues(bool $includeNull = false): array { @@ -211,10 +198,6 @@ protected function getInvalidDocumentValues(bool $includeNull = false): array /** * Return a list of invalid integer values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidIntegerValues(bool $includeNull = false): array { @@ -223,10 +206,6 @@ protected function getInvalidIntegerValues(bool $includeNull = false): array /** * Return a list of invalid ReadPreference values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidReadConcernValues(bool $includeNull = false): array { @@ -235,10 +214,6 @@ protected function getInvalidReadConcernValues(bool $includeNull = false): array /** * Return a list of invalid ReadPreference values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidReadPreferenceValues(bool $includeNull = false): array { @@ -247,10 +222,6 @@ protected function getInvalidReadPreferenceValues(bool $includeNull = false): ar /** * Return a list of invalid Session values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidSessionValues(bool $includeNull = false): array { @@ -259,10 +230,6 @@ protected function getInvalidSessionValues(bool $includeNull = false): array /** * Return a list of invalid string values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidStringValues(bool $includeNull = false): array { @@ -271,10 +238,6 @@ protected function getInvalidStringValues(bool $includeNull = false): array /** * Return a list of invalid WriteConcern values. - * - * @param boolean $includeNull - * - * @return array */ protected function getInvalidWriteConcernValues(bool $includeNull = false): array { @@ -283,8 +246,6 @@ protected function getInvalidWriteConcernValues(bool $includeNull = false): arra /** * Return the test namespace. - * - * @return string */ protected function getNamespace(): string { @@ -295,7 +256,6 @@ protected function getNamespace(): string * Wrap a list of values for use as a single-argument data provider. * * @param array $values List of values - * @return array */ protected function wrapValuesForDataProvider(array $values): array { diff --git a/tests/UnifiedSpecTests/Context.php b/tests/UnifiedSpecTests/Context.php index 39e3f5d1f..2300965f3 100644 --- a/tests/UnifiedSpecTests/Context.php +++ b/tests/UnifiedSpecTests/Context.php @@ -91,8 +91,6 @@ public function setUrisForUseMultipleMongoses(string $singleMongosUri, string $m /** * Create entities for "createEntities". - * - * @param array $createEntities */ public function createEntities(array $entities): void { diff --git a/tests/UnifiedSpecTests/EventCollector.php b/tests/UnifiedSpecTests/EventCollector.php index 1da92832c..98465a1a3 100644 --- a/tests/UnifiedSpecTests/EventCollector.php +++ b/tests/UnifiedSpecTests/EventCollector.php @@ -163,8 +163,7 @@ private static function getConnectionId($event): string return sprintf('%s:%d', $server->getHost(), $server->getPort()); } - /** @param object $event */ - private static function getEventName($event): string + private static function getEventName(object $event): string { static $eventNamesByClass = null; From 07b48fc6e4d6af0b0170081caea568086f2ad1fa Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Sep 2022 15:22:58 -0400 Subject: [PATCH 198/321] PHPLIB-947: Skip legacy CSFLE explain test pending crypt_shared fix (#972) --- tests/SpecTests/ClientSideEncryptionSpecTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 4fb9bad70..7fff25e6d 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -65,6 +65,7 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase 'awsTemporary: Insert a document with auto encryption using the AWS provider with temporary credentials' => 'Not yet implemented (PHPC-1751)', 'awsTemporary: Insert with invalid temporary credentials' => 'Not yet implemented (PHPC-1751)', 'azureKMS: Insert a document with auto encryption using Azure KMS provider' => 'RHEL platform is missing Azure root certificate (PHPLIB-619)', + 'explain: Explain a find with deterministic encryption' => 'crypt_shared does not add apiVersion field to explain commands (PHPLIB-947, SERVER-69564)', 'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)', 'timeoutMS: remaining timeoutMS applied to find to get keyvault data' => 'Not yet implemented (PHPC-1760)', ]; From aa04362fa95d9bb17861d22322f8ecf3ca058fee Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 16 Sep 2022 09:04:58 +0200 Subject: [PATCH 199/321] PHPLIB-610: Psalm Integration (#973) * Add base psalm configuration * Run psalm on GitHub Actions * Fix psalm errors * Use development version of psalm The upcoming release will include an updated callmap for the MongoDB classes. * Add unfixable error to psalm baseline * Enforce psalm errorLevel 1 for new code Existing errors are added to the baseline, meaning that new code needs to adhere to the strictest psalm level. * Run coding standards and static analysis checks on feature branches * Add contribution docs for psalm * Improve ChangeStreamIterator handling of wrapped iterator * Specify callable explicitly in ChangeStream * Make null coalesce within ternary more readable * Rewrite conditional to avoid suppressing psalm errors * Move psalm config to dist file * Add comment about ChangeStreamIterator::getInnerIterator --- .github/workflows/coding-standards.yml | 6 +- .github/workflows/static-analysis.yml | 68 ++ .gitignore | 3 + CONTRIBUTING.md | 26 + composer.json | 3 +- psalm-baseline.xml | 823 ++++++++++++++++++ psalm.xml.dist | 16 + src/BulkWriteResult.php | 8 +- src/ChangeStream.php | 12 +- src/Client.php | 2 +- src/DeleteResult.php | 2 +- src/GridFS/Bucket.php | 8 +- src/GridFS/CollectionWrapper.php | 12 +- src/GridFS/Exception/CorruptFileException.php | 8 + src/GridFS/ReadableStream.php | 24 +- src/GridFS/StreamWrapper.php | 14 + src/GridFS/WritableStream.php | 7 +- src/InsertManyResult.php | 2 +- src/InsertOneResult.php | 2 +- src/Model/ChangeStreamIterator.php | 26 +- src/Operation/Aggregate.php | 5 +- src/Operation/Count.php | 2 +- src/Operation/CountDocuments.php | 6 +- src/Operation/DatabaseCommand.php | 2 +- src/Operation/Distinct.php | 2 +- src/Operation/DropCollection.php | 1 + src/Operation/FindAndModify.php | 2 +- src/Operation/MapReduce.php | 2 + src/Operation/RenameCollection.php | 1 + src/Operation/Watch.php | 12 +- src/UpdateResult.php | 4 +- src/functions.php | 10 +- 32 files changed, 1071 insertions(+), 50 deletions(-) create mode 100644 .github/workflows/static-analysis.yml create mode 100644 psalm-baseline.xml create mode 100644 psalm.xml.dist diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 27f53b834..06b999ced 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -5,14 +5,16 @@ on: branches: - "v*.*" - "master" + - "feature/*" push: branches: - "v*.*" - "master" + - "feature/*" jobs: - coding-standards: - name: "Coding Standards" + phpcs: + name: "phpcs" runs-on: "ubuntu-20.04" strategy: diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 000000000..a1a09ca43 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,68 @@ +name: "Static Analysis" + +on: + pull_request: + branches: + - "v*.*" + - "master" + - "feature/*" + push: + branches: + - "v*.*" + - "master" + - "feature/*" + +jobs: + psalm: + name: "Psalm" + runs-on: "ubuntu-20.04" + + strategy: + matrix: + php-version: + - "7.4" + driver-version: + - "mongodb/mongo-php-driver@master" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: Setup cache environment + id: extcache + uses: shivammathur/cache-extensions@v1 + with: + php-version: ${{ matrix.php-version }} + extensions: "mongodb-${{ matrix.driver-version }}" + key: "extcache-v1" + + - name: Cache extensions + uses: actions/cache@v2 + with: + path: ${{ steps.extcache.outputs.dir }} + key: ${{ steps.extcache.outputs.key }} + restore-keys: ${{ steps.extcache.outputs.key }} + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + extensions: "mongodb-${{ matrix.driver-version }}" + php-version: "${{ matrix.php-version }}" + tools: "cs2pr" + + - name: "Show driver information" + run: "php --ri mongodb" + + - name: "Cache dependencies installed with Composer" + uses: "actions/cache@v2" + with: + path: "~/.composer/cache" + key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-locked-" + + - name: "Install dependencies with Composer" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Run Psalm" + run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)" diff --git a/.gitignore b/.gitignore index ee520b98e..e8e8c841b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,7 @@ phpunit.xml .phpcs-cache phpcs.xml +# psalm +psalm.xml + mongocryptd.pid diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 80fabae48..c43f249d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -122,6 +122,32 @@ To automatically fix all fixable errors, use the `phpcbf` binary: $ vendor/bin/phpcbf ``` +## Running static analysis + +The library uses [psalm](https://psalm.dev) to run static analysis on the code +and ensure an additional level of type safety. New code is expected to adhere +to level 1, with a baseline covering existing issues. To run static analysis +checks, run the `psalm` binary: + +``` +$ vendor/bin/psalm +``` + +To remove fixed errors from the baseline, you can use the `update-baseline` +command-line argument: + +``` +$ vendor/bin/psalm --update-baseline +``` + +Note that this will not add new errors to the baseline. New errors should be +fixed instead of being added to the technical debt, but in case this isn't +possible it can be added to the baseline using `set-baseline`: + +``` +$ vendor/bin/psalm --set-baseline=psalm-baseline.xml +``` + ## Documentation Documentation for the library lives in the `docs/` directory and is built with diff --git a/composer.json b/composer.json index 2117537b2..f51b0b192 100644 --- a/composer.json +++ b/composer.json @@ -19,7 +19,8 @@ "require-dev": { "squizlabs/php_codesniffer": "^3.6", "doctrine/coding-standard": "^9.0", - "symfony/phpunit-bridge": "^5.2" + "symfony/phpunit-bridge": "^5.2", + "vimeo/psalm": "^4.x-dev" }, "autoload": { "psr-4": { "MongoDB\\": "src/" }, diff --git a/psalm-baseline.xml b/psalm-baseline.xml new file mode 100644 index 000000000..952117897 --- /dev/null +++ b/psalm-baseline.xml @@ -0,0 +1,823 @@ + + + + + $driverOptions['driver'] ?? [] + + + $mergedDriver['platform'] + + + + + $encryptedFields['eccCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecc' + $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecoc' + $encryptedFields['escCollection'] ?? 'enxcol_.' . $this->collectionName . '.esc' + + + $encryptedFields + + + + + $cmd[$option] + $options['session'] + + + + + $cmd[$option] + $options['session'] + + + + + $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc' + $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc' + $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc' + $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc' + $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc' + $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc' + + + $encryptedFields + $encryptedFields + $options['encryptedFields'] + + + + + new static(sprintf('%s is immutable', $class)) + new static(sprintf('%s should not be called for an unacknowledged write result', $method)) + + + + + new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, get_debug_type($value))) + + + + + new static('Resume token not found in change document') + new static(sprintf('Expected resume token to have type "array or object" but found "%s"', get_debug_type($value))) + + + + + new static('Array filters are not supported by the server executing this operation') + new static('Collations are not supported by the server executing this operation') + new static('Explain is not supported by the server executing this operation') + new static('Hint is not supported by the server executing this operation') + new static('Read concern is not supported by the server executing this command') + new static('The "allowDiskUse" option is not supported by the server executing this operation') + new static('The "commitQuorum" option is not supported by the server executing this operation') + new static('The "readConcern" option cannot be specified within a transaction. Instead, specify it when starting the transaction.') + new static('The "writeConcern" option cannot be specified within a transaction. Instead, specify it when starting the transaction.') + new static('Write concern is not supported by the server executing this command') + + + + + ! is_resource($destination) + ! is_resource($destination) + ! is_resource($source) + ! is_resource($stream) + + + delete + downloadToStream + downloadToStreamByName + drop + rename + + + $id + $options['revision'] + $options['revision'] + + + $id + + + + + new static(sprintf('Chunk not found for index "%d"', $expectedIndex)) + new static(sprintf('Expected chunk to have index "%d" but found "%d"', $expectedIndex, $index)) + new static(sprintf('Expected chunk to have size "%d" but found "%d"', $expectedSize, $size)) + new static(sprintf('Invalid data found for index "%d"', $chunkIndex)) + + + + + $json + + + $json + + + new static(sprintf('File "%s" not found in "%s"', $json, $namespace)) + new static(sprintf('File with name "%s" and revision "%d" not found in "%s"', $filename, $revision, $namespace)) + + + + + $idString + + + $idString + + + new static(sprintf('Downloading file from "%s" to "%s" failed. GridFS filename: "%s"', $sourceMetadata['uri'], $destinationMetadata['uri'], $filename)) + new static(sprintf('Downloading file from "%s" to "%s" failed. GridFS identifier: "%s"', $sourceMetadata['uri'], $destinationMetadata['uri'], $idString)) + new static(sprintf('Uploading file from "%s" to "%s" failed. GridFS filename: "%s"', $sourceMetadata['uri'], $destinationUri, $filename)) + + + + + $currentChunk->n + $this->file->length + + + + + $context[$this->protocol]['collectionWrapper'] + $context[$this->protocol]['collectionWrapper'] + $context[$this->protocol]['file'] + $context[$this->protocol]['filename'] + $context[$this->protocol]['options'] + + + $context[$this->protocol]['collectionWrapper'] + $context[$this->protocol]['collectionWrapper'] + $context[$this->protocol]['file'] + $context[$this->protocol]['filename'] + $context[$this->protocol]['options'] + + + stream_wrapper_unregister + + + + + hash_update + + + + + Traversable + + + call_user_func($this->getIterator) + + + + + $this[$key] + + + $key + $this[$key] + $value + + + new static() + + + + + $iteratorClass + + + $this[$key] + + + $key + $this[$key] + $value + + + new static() + + + + + $documentLength + $documentLength + $this->options['typeMap'] + + + $this->position + + + $documentLength + + + + + $currentItem[self::FIELD_KEY] + $currentItem[self::FIELD_VALUE] + + + $currentItem + $currentItem + + + + + ! is_array($document) && ! is_object($document) + isset($initialResumeToken) && ! is_array($initialResumeToken) && ! is_object($initialResumeToken) + + + $reply->cursor->nextBatch + $this->current() + + + $this->postBatchResumeToken + + + $reply->cursor->nextBatch + $reply->cursor->postBatchResumeToken + + + addSubscriber + removeSubscriber + + + + + $key + + + $this->info[$key] + + + + + $info + + + $info['idIndex']['ns'] + + + $info + + + $info['name'] + + + + + $key + + + $this->info[$key] + + + + + current($this->databases) + + + int + key($this->databases) + + + + + $key + + + $this->info[$key] + + + + + $info + $info + + + $info['ns'] + + + $info + + + + + $fieldName + + + $fieldName + + + $this->index['name'] + + + + + $this->options['typeMap'] + $this->options['typeMap'] + + + $cmdOptions['maxAwaitTimeMS'] + $cmd[$option] + $cmd['hint'] + $options[$option] + $options['writeConcern'] + + + isDefault + isDefault + isInTransaction + + + + + is_array($operation) + + + $args + $args + $args + $args[0] + $args[0] + $args[0] + $args[1] + $args[1] + $args[1] + $args[1] + $args[2] + + + $args[0] + $args[0] + $args[0] + $args[1] + $args[1] + $args[1] + $args[1] + $args[1] + $args[1] + $args[1] + $args[1] + $args[1] + $args[1] + $args[2] + $args[2] + $args[2] + $args[2] + $args[2] + $args[2] + $args[2] + $args[2]['upsert'] + $args[2]['upsert'] + $args[2]['upsert'] + $args[2]['upsert'] + + + $args[1] + $args[1] + $args[2] + $args[2] + $args[2] + $args[2] + $args[2] + $args[2] + $operations[$i][$type][1] + $operations[$i][$type][2] + $operations[$i][$type][2] + + + $args + $args + $args[2] + $args[2] + $insertedIds[$i] + $operations[$i][$type][1] + $operations[$i][$type][2] + $operations[$i][$type][2] + $options[$option] + $options['session'] + $options['writeConcern'] + + + isDefault + isInTransaction + + + $args[2] + $args[2] + + + + + ! is_array($filter) && ! is_object($filter) + + + $cmd[$option] + $cmd['hint'] + $options['readConcern'] + $options['readPreference'] + $options['session'] + + + isInTransaction + + + + + ! is_array($filter) && ! is_object($filter) + + + + + $i + $i + $this->options['typeMap'] + + + $cmd[$option] + $options['session'] + $options['writeConcern'] + + + + + is_array($index) + + + $cmd[$option] + $cmd['commitQuorum'] + $options['session'] + $options['writeConcern'] + + + isInTransaction + + + + + ! is_array($command) && ! is_object($command) + + + $this->options['typeMap'] + + + $options['readPreference'] + $options['session'] + + + + + ! is_array($filter) && ! is_object($filter) + + + $this->options['writeConcern'] + + + $cmd['writeConcern'] + $deleteOptions['hint'] + $options['comment'] + $options['session'] + $options['writeConcern'] + + + isInTransaction + + + + + ! is_array($filter) && ! is_object($filter) + + + $this->options['typeMap'] + + + $cmd[$option] + $options['readConcern'] + $options['readPreference'] + $options['session'] + + + isInTransaction + + + + + $this->options['typeMap'] + + + $cmd['comment'] + $options['session'] + $options['writeConcern'] + + + isInTransaction + + + + + $this->options['typeMap'] + + + $cmd['comment'] + $options['session'] + $options['writeConcern'] + + + + + $this->options['typeMap'] + + + $cmd[$option] + $options['session'] + $options['writeConcern'] + + + isInTransaction + + + + + $this->options['typeMap'] + + + $cmd[$option] + $options['readPreference'] + $options['session'] + + + + + ! is_array($filter) && ! is_object($filter) + + + $this->options['typeMap'] + + + $options['modifiers'][$modifier[1]] + + + $options[$modifier[0]] + $options[$option] + $options['readPreference'] + $options['session'] + + + isInTransaction + + + + + $this->options['typeMap'] + $this->options['writeConcern'] + + + $cmd[$option] + $cmd['new'] + $cmd['update'] + $cmd['upsert'] + $options['session'] + $options['writeConcern'] + + + array|object|null + + + isDefault + isInTransaction + + + is_object($result) ? ($result->value ?? null) : null + + + + + ! is_array($filter) && ! is_object($filter) + + + + + ! is_array($filter) && ! is_object($filter) + ! is_array($replacement) && ! is_object($replacement) + + + $options['returnDocument'] + + + + + ! is_array($filter) && ! is_object($filter) + ! is_array($update) && ! is_object($update) + + + $options['returnDocument'] + + + + + ! is_array($document) && ! is_object($document) + + + $insertedIds[$i] + $options[$option] + $options['session'] + $options['writeConcern'] + + + isDefault + isInTransaction + + + + + ! is_array($document) && ! is_object($document) + + + $insertedId + $options[$option] + $options['session'] + $options['writeConcern'] + + + isDefault + isInTransaction + + + + + function (array $collectionInfo) { + + + + + $cmd[$option] + $options['session'] + + + + + ! is_string($out) && ! is_array($out) && ! is_object($out) + + + $result->result->collection + $result->result->db + $this->options['typeMap'] + + + $cmd[$option] + $options['readConcern'] + $options['readPreference'] + $options['session'] + $options['writeConcern'] + + + getScope + isDefault + isDefault + isInTransaction + + + + + $this->options['typeMap'] + + + $cmd['comment'] + $options['session'] + $options['writeConcern'] + + + + + $this->options['typeMap'] + + + $cmd[$option] + $options['session'] + $options['writeConcern'] + + + isInTransaction + + + + + ! is_array($replacement) && ! is_object($replacement) + + + + + ! is_array($filter) && ! is_object($filter) + ! is_array($update) && ! is_object($update) + + + $this->options['writeConcern'] + + + $cmd['bypassDocumentValidation'] + $cmd['writeConcern'] + $options[$option] + $options['session'] + $options['writeConcern'] + $updateOptions[$option] + + + isDefault + isInTransaction + + + + + ! is_array($update) && ! is_object($update) + + + + + ! is_array($update) && ! is_object($update) + + + + + isset($resumeToken) && ! is_array($resumeToken) && ! is_object($resumeToken) + + + $reply->cursor->firstBatch + + + $this->postBatchResumeToken + + + array|object|null + + + $reply->cursor->firstBatch + $reply->cursor->postBatchResumeToken + + + $this->changeStreamOptions['resumeAfter'] + $this->changeStreamOptions['startAfter'] + + + $firstBatchSize + $operationTime + + + $resumeToken === null && $this->operationTime !== null + $this->operationTime !== null + + + addSubscriber + removeSubscriber + + + + + $id + + + + + ! is_array($document) && ! is_object($document) + is_array($document) + is_array($document) + is_array($out) + + + $wireVersionForWriteStageOnSecondary + + + $manager->getServers() + + + $collectionInfo['options']['encryptedFields'] + + + $typeMap['fieldPaths'][$fieldPath] + $typeMap['fieldPaths'][substr($fieldPath, 0, -2)] + + + $element[$key] + $lastOp + $type + $type + $typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath] + $typeMap['fieldPaths'][$fieldPath] + $value + + + array|object + array|object|null + array|object|null + + + $type + + + $collectionInfo['options']['encryptedFields'] ?? null + $encryptedFieldsMap[$databaseName . '.' . $collectionName] ?? null + toPHP(fromPHP($document), $typeMap) + + + diff --git a/psalm.xml.dist b/psalm.xml.dist new file mode 100644 index 000000000..8cf6c4435 --- /dev/null +++ b/psalm.xml.dist @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/src/BulkWriteResult.php b/src/BulkWriteResult.php index 731c49294..dec8d59de 100644 --- a/src/BulkWriteResult.php +++ b/src/BulkWriteResult.php @@ -47,7 +47,7 @@ public function __construct(WriteResult $writeResult, array $insertedIds) * This method should only be called if the write was acknowledged. * * @see BulkWriteResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getDeletedCount() @@ -65,7 +65,7 @@ public function getDeletedCount() * This method should only be called if the write was acknowledged. * * @see BulkWriteResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getInsertedCount() @@ -99,7 +99,7 @@ public function getInsertedIds() * This method should only be called if the write was acknowledged. * * @see BulkWriteResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getMatchedCount() @@ -138,7 +138,7 @@ public function getModifiedCount() * This method should only be called if the write was acknowledged. * * @see BulkWriteResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getUpsertedCount() diff --git a/src/ChangeStream.php b/src/ChangeStream.php index cfd10e6f4..33c461801 100644 --- a/src/ChangeStream.php +++ b/src/ChangeStream.php @@ -22,6 +22,7 @@ use MongoDB\Driver\Exception\ConnectionException; use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\Exception\ServerException; +use MongoDB\Exception\BadMethodCallException; use MongoDB\Exception\ResumeTokenException; use MongoDB\Model\ChangeStreamIterator; use ReturnTypeWillChange; @@ -32,6 +33,8 @@ /** * Iterator for a change stream. * + * @psalm-type ResumeCallable = callable(array|object|null, bool): ChangeStreamIterator + * * @api * @see \MongoDB\Collection::watch() * @see https://mongodb.com/docs/manual/reference/method/db.watch/#mongodb-method-db.watch @@ -71,7 +74,7 @@ class ChangeStream implements Iterator /** @var int */ private static $wireVersionForResumableChangeStreamError = 9; - /** @var callable */ + /** @var ResumeCallable|null */ private $resumeCallable; /** @var ChangeStreamIterator */ @@ -90,6 +93,8 @@ class ChangeStream implements Iterator /** * @internal + * + * @param ResumeCallable $resumeCallable */ public function __construct(ChangeStreamIterator $iterator, callable $resumeCallable) { @@ -250,7 +255,12 @@ private function onIteration(bool $incrementKey): void */ private function resume(): void { + if (! $this->resumeCallable) { + throw new BadMethodCallException('Cannot resume a closed change stream.'); + } + $this->iterator = call_user_func($this->resumeCallable, $this->getResumeToken(), $this->hasAdvanced); + $this->iterator->rewind(); $this->onIteration($this->hasAdvanced); diff --git a/src/Client.php b/src/Client.php index 7f15ba12b..0fd339081 100644 --- a/src/Client.php +++ b/src/Client.php @@ -117,7 +117,7 @@ public function __construct(string $uri = 'mongodb://127.0.0.1/', array $uriOpti $driverOptions['driver'] = $this->mergeDriverInfo($driverOptions['driver'] ?? []); $this->uri = $uri; - $this->typeMap = $driverOptions['typeMap'] ?? null; + $this->typeMap = $driverOptions['typeMap']; unset($driverOptions['typeMap']); diff --git a/src/DeleteResult.php b/src/DeleteResult.php index 5666307f2..697ee8692 100644 --- a/src/DeleteResult.php +++ b/src/DeleteResult.php @@ -43,7 +43,7 @@ public function __construct(WriteResult $writeResult) * This method should only be called if the write was acknowledged. * * @see DeleteResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getDeletedCount() diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php index 33f6616a7..67ad9ffd8 100644 --- a/src/GridFS/Bucket.php +++ b/src/GridFS/Bucket.php @@ -34,6 +34,7 @@ use MongoDB\Operation\Find; use function array_intersect_key; +use function assert; use function fopen; use function get_resource_type; use function in_array; @@ -412,6 +413,7 @@ public function getFileIdForStream($stream) */ $typeMap = ['root' => 'stdClass'] + $this->typeMap; $file = apply_type_map_to_document($file, $typeMap); + assert(is_object($file)); if (! isset($file->_id) && ! property_exists($file, '_id')) { throw new CorruptFileException('file._id does not exist'); @@ -643,10 +645,10 @@ public function uploadFromStream(string $filename, $source, array $options = []) */ private function createPathForFile(object $file): string { - if (! is_object($file->_id) || method_exists($file->_id, '__toString')) { - $id = (string) $file->_id; - } else { + if (is_array($file->_id) || (is_object($file->_id) && ! method_exists($file->_id, '__toString'))) { $id = toJSON(fromPHP(['_id' => $file->_id])); + } else { + $id = (string) $file->_id; } return sprintf( diff --git a/src/GridFS/CollectionWrapper.php b/src/GridFS/CollectionWrapper.php index f4d4d76dc..28218707c 100644 --- a/src/GridFS/CollectionWrapper.php +++ b/src/GridFS/CollectionWrapper.php @@ -27,8 +27,10 @@ use MultipleIterator; use function abs; +use function assert; use function count; use function is_numeric; +use function is_object; use function sprintf; /** @@ -150,7 +152,7 @@ public function findFileByFilenameAndRevision(string $filename, int $revision): $sortOrder = 1; } - return $this->filesCollection->findOne( + $file = $this->filesCollection->findOne( ['filename' => $filename], [ 'skip' => $skip, @@ -158,6 +160,9 @@ public function findFileByFilenameAndRevision(string $filename, int $revision): 'typeMap' => ['root' => 'stdClass'], ] ); + assert(is_object($file) || $file === null); + + return $file; } /** @@ -167,10 +172,13 @@ public function findFileByFilenameAndRevision(string $filename, int $revision): */ public function findFileById($id): ?object { - return $this->filesCollection->findOne( + $file = $this->filesCollection->findOne( ['_id' => $id], ['typeMap' => ['root' => 'stdClass']] ); + assert(is_object($file) || $file === null); + + return $file; } /** diff --git a/src/GridFS/Exception/CorruptFileException.php b/src/GridFS/Exception/CorruptFileException.php index 7879cb1ec..e31d7daeb 100644 --- a/src/GridFS/Exception/CorruptFileException.php +++ b/src/GridFS/Exception/CorruptFileException.php @@ -23,6 +23,14 @@ class CorruptFileException extends RuntimeException { + /** + * Thrown when a chunk doesn't contain valid data. + */ + public static function invalidChunkData(int $chunkIndex): self + { + return new static(sprintf('Invalid data found for index "%d"', $chunkIndex)); + } + /** * Thrown when a chunk is not found for an expected index. * diff --git a/src/GridFS/ReadableStream.php b/src/GridFS/ReadableStream.php index 9672b803f..d76e06172 100644 --- a/src/GridFS/ReadableStream.php +++ b/src/GridFS/ReadableStream.php @@ -17,13 +17,16 @@ namespace MongoDB\GridFS; -use MongoDB\Driver\CursorInterface; +use MongoDB\BSON\Binary; +use MongoDB\Driver\Cursor; use MongoDB\Exception\InvalidArgumentException; use MongoDB\GridFS\Exception\CorruptFileException; +use function assert; use function ceil; use function floor; use function is_integer; +use function is_object; use function property_exists; use function sprintf; use function strlen; @@ -48,13 +51,13 @@ class ReadableStream /** @var integer */ private $chunkOffset = 0; - /** @var CursorInterface|null */ + /** @var Cursor|null */ private $chunksIterator; /** @var CollectionWrapper */ private $collectionWrapper; - /** @var float|integer */ + /** @var integer */ private $expectedLastChunkSize = 0; /** @var object */ @@ -164,6 +167,8 @@ public function readBytes(int $length): string return ''; } + assert($this->buffer !== null); + $data = ''; while (strlen($data) < $length) { @@ -250,16 +255,25 @@ private function initBufferFromCurrentChunk(): bool return false; } + if ($this->chunksIterator === null) { + return false; + } + if (! $this->chunksIterator->valid()) { throw CorruptFileException::missingChunk($this->chunkOffset); } $currentChunk = $this->chunksIterator->current(); + assert(is_object($currentChunk)); if ($currentChunk->n !== $this->chunkOffset) { throw CorruptFileException::unexpectedIndex($currentChunk->n, $this->chunkOffset); } + if (! $currentChunk->data instanceof Binary) { + throw CorruptFileException::invalidChunkData($this->chunkOffset); + } + $this->buffer = $currentChunk->data->getData(); $actualChunkSize = strlen($this->buffer); @@ -287,6 +301,10 @@ private function initBufferFromNextChunk(): bool return false; } + if ($this->chunksIterator === null) { + return false; + } + $this->bufferOffset = 0; $this->chunkOffset++; $this->chunksIterator->next(); diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index 268c47ea7..3e04c3d14 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -19,9 +19,11 @@ use MongoDB\BSON\UTCDateTime; +use function assert; use function explode; use function in_array; use function is_integer; +use function is_resource; use function stream_context_get_options; use function stream_get_wrappers; use function stream_wrapper_register; @@ -66,6 +68,8 @@ public function __destruct() */ public function getFile(): object { + assert($this->stream !== null); + return $this->stream->getFile(); } @@ -164,6 +168,8 @@ public function stream_read(int $length): string */ public function stream_seek(int $offset, int $whence = SEEK_SET): bool { + assert($this->stream !== null); + $size = $this->stream->getSize(); if ($whence === SEEK_CUR) { @@ -195,6 +201,8 @@ public function stream_seek(int $offset, int $whence = SEEK_SET): bool */ public function stream_stat(): array { + assert($this->stream !== null); + $stat = $this->getStatTemplate(); $stat[2] = $stat['mode'] = $this->stream instanceof ReadableStream @@ -225,6 +233,8 @@ public function stream_stat(): array */ public function stream_tell(): int { + assert($this->stream !== null); + return $this->stream->tell(); } @@ -286,8 +296,10 @@ private function initProtocol(string $path): void */ private function initReadableStream(): bool { + assert(is_resource($this->context)); $context = stream_context_get_options($this->context); + assert($this->protocol !== null); $this->stream = new ReadableStream( $context[$this->protocol]['collectionWrapper'], $context[$this->protocol]['file'] @@ -303,8 +315,10 @@ private function initReadableStream(): bool */ private function initWritableStream(): bool { + assert(is_resource($this->context)); $context = stream_context_get_options($this->context); + assert($this->protocol !== null); $this->stream = new WritableStream( $context[$this->protocol]['collectionWrapper'], $context[$this->protocol]['filename'], diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php index b80a8ce6b..43519e09b 100644 --- a/src/GridFS/WritableStream.php +++ b/src/GridFS/WritableStream.php @@ -17,6 +17,7 @@ namespace MongoDB\GridFS; +use HashContext; use MongoDB\BSON\Binary; use MongoDB\BSON\ObjectId; use MongoDB\BSON\UTCDateTime; @@ -65,7 +66,7 @@ class WritableStream /** @var array */ private $file; - /** @var resource */ + /** @var HashContext|null */ private $hashCtx; /** @var boolean */ @@ -262,7 +263,7 @@ private function fileCollectionInsert() $this->file['length'] = $this->length; $this->file['uploadDate'] = new UTCDateTime(); - if (! $this->disableMD5) { + if (! $this->disableMD5 && $this->hashCtx) { $this->file['md5'] = hash_final($this->hashCtx); } @@ -292,7 +293,7 @@ private function insertChunkFromBuffer(): void 'data' => new Binary($data, Binary::TYPE_GENERIC), ]; - if (! $this->disableMD5) { + if (! $this->disableMD5 && $this->hashCtx) { hash_update($this->hashCtx, $data); } diff --git a/src/InsertManyResult.php b/src/InsertManyResult.php index 87fd60eef..d1aabe558 100644 --- a/src/InsertManyResult.php +++ b/src/InsertManyResult.php @@ -47,7 +47,7 @@ public function __construct(WriteResult $writeResult, array $insertedIds) * This method should only be called if the write was acknowledged. * * @see InsertManyResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getInsertedCount() diff --git a/src/InsertOneResult.php b/src/InsertOneResult.php index 4376b6bdf..6a74eb900 100644 --- a/src/InsertOneResult.php +++ b/src/InsertOneResult.php @@ -50,7 +50,7 @@ public function __construct(WriteResult $writeResult, $insertedId) * This method should only be called if the write was acknowledged. * * @see InsertOneResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getInsertedCount() diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php index 85fba283d..ceb31f9fc 100644 --- a/src/Model/ChangeStreamIterator.php +++ b/src/Model/ChangeStreamIterator.php @@ -30,9 +30,9 @@ use MongoDB\Exception\UnexpectedValueException; use ReturnTypeWillChange; +use function assert; use function count; use function is_array; -use function is_integer; use function is_object; use function MongoDB\Driver\Monitoring\addSubscriber; use function MongoDB\Driver\Monitoring\removeSubscriber; @@ -75,18 +75,10 @@ class ChangeStreamIterator extends IteratorIterator implements CommandSubscriber */ public function __construct(Cursor $cursor, int $firstBatchSize, $initialResumeToken, ?object $postBatchResumeToken) { - if (! is_integer($firstBatchSize)) { - throw InvalidArgumentException::invalidType('$firstBatchSize', $firstBatchSize, 'integer'); - } - if (isset($initialResumeToken) && ! is_array($initialResumeToken) && ! is_object($initialResumeToken)) { throw InvalidArgumentException::invalidType('$initialResumeToken', $initialResumeToken, 'array or object'); } - if (isset($postBatchResumeToken) && ! is_object($postBatchResumeToken)) { - throw InvalidArgumentException::invalidType('$postBatchResumeToken', $postBatchResumeToken, 'object'); - } - parent::__construct($cursor); $this->batchSize = $firstBatchSize; @@ -109,7 +101,7 @@ final public function commandStarted(CommandStartedEvent $event): void } $this->batchPosition = 0; - $this->batchSize = null; + $this->batchSize = 0; $this->postBatchResumeToken = null; } @@ -143,6 +135,20 @@ public function current() return $this->isValid ? parent::current() : null; } + /** + * Necessary to let psalm know that we're always expecting a cursor as inner + * iterator. This could be side-stepped due to the class not being final, + * but it's very much an invalid use-case. This method can be dropped in 2.0 + * once the class is final. + */ + final public function getInnerIterator(): Cursor + { + $cursor = parent::getInnerIterator(); + assert($cursor instanceof Cursor); + + return $cursor; + } + /** * Returns the resume token for the iterator's current position. * diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php index f529be022..040e3c9c9 100644 --- a/src/Operation/Aggregate.php +++ b/src/Operation/Aggregate.php @@ -30,7 +30,6 @@ use MongoDB\Exception\UnexpectedValueException; use MongoDB\Exception\UnsupportedException; use stdClass; -use Traversable; use function current; use function is_array; @@ -256,7 +255,7 @@ public function __construct(string $databaseName, ?string $collectionName, array * Execute the operation. * * @see Executable::execute() - * @return Traversable + * @return ArrayIterator|Cursor * @throws UnexpectedValueException if the command response was malformed * @throws UnsupportedException if read concern or write concern is used and unsupported * @throws DriverRuntimeException for other driver errors (e.g. connection errors) @@ -295,7 +294,7 @@ public function execute(Server $server) $result = current($cursor->toArray()); - if (! isset($result->result) || ! is_array($result->result)) { + if (! is_object($result) || ! isset($result->result) || ! is_array($result->result)) { throw new UnexpectedValueException('aggregate command did not return a "result" array'); } diff --git a/src/Operation/Count.php b/src/Operation/Count.php index b72bc34bf..7e427313c 100644 --- a/src/Operation/Count.php +++ b/src/Operation/Count.php @@ -158,7 +158,7 @@ public function execute(Server $server) $result = current($cursor->toArray()); // Older server versions may return a float - if (! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) { + if (! is_object($result) || ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) { throw new UnexpectedValueException('count command did not return a numeric "n" value'); } diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php index cc5534d28..57b04544b 100644 --- a/src/Operation/CountDocuments.php +++ b/src/Operation/CountDocuments.php @@ -17,6 +17,7 @@ namespace MongoDB\Operation; +use MongoDB\Driver\Cursor; use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\Server; use MongoDB\Exception\InvalidArgumentException; @@ -24,6 +25,7 @@ use MongoDB\Exception\UnsupportedException; use function array_intersect_key; +use function assert; use function count; use function current; use function is_array; @@ -129,6 +131,8 @@ public function __construct(string $databaseName, string $collectionName, $filte public function execute(Server $server) { $cursor = $this->aggregate->execute($server); + assert($cursor instanceof Cursor); + $allResults = $cursor->toArray(); /* If there are no documents to count, the aggregation pipeline has no items to group, and @@ -138,7 +142,7 @@ public function execute(Server $server) } $result = current($allResults); - if (! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) { + if (! is_object($result) || ! isset($result->n) || ! (is_integer($result->n) || is_float($result->n))) { throw new UnexpectedValueException('count command did not return a numeric "n" value'); } diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php index a0f48fae0..4e6fac522 100644 --- a/src/Operation/DatabaseCommand.php +++ b/src/Operation/DatabaseCommand.php @@ -38,7 +38,7 @@ class DatabaseCommand implements Executable /** @var string */ private $databaseName; - /** @var array|Command|object */ + /** @var Command */ private $command; /** @var array */ diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php index d957bfc29..3c2f93dbd 100644 --- a/src/Operation/Distinct.php +++ b/src/Operation/Distinct.php @@ -151,7 +151,7 @@ public function execute(Server $server) $result = current($cursor->toArray()); - if (! isset($result->values) || ! is_array($result->values)) { + if (! is_object($result) || ! isset($result->values) || ! is_array($result->values)) { throw new UnexpectedValueException('distinct command did not return a "values" array'); } diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php index 846dca4a7..11e85bdd7 100644 --- a/src/Operation/DropCollection.php +++ b/src/Operation/DropCollection.php @@ -19,6 +19,7 @@ use MongoDB\Driver\Command; use MongoDB\Driver\Exception\CommandException; +use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php index c5103a8a0..d4fc2b3a4 100644 --- a/src/Operation/FindAndModify.php +++ b/src/Operation/FindAndModify.php @@ -253,7 +253,7 @@ public function execute(Server $server) $result = current($cursor->toArray()); - return $result->value ?? null; + return is_object($result) ? ($result->value ?? null) : null; } /** diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php index 97e22f080..7b97dd0a9 100644 --- a/src/Operation/MapReduce.php +++ b/src/Operation/MapReduce.php @@ -32,6 +32,7 @@ use MongoDB\MapReduceResult; use stdClass; +use function assert; use function current; use function is_array; use function is_bool; @@ -301,6 +302,7 @@ public function execute(Server $server) } $result = current($cursor->toArray()); + assert($result instanceof stdClass); $getIterator = $this->createGetIteratorCallable($result, $server); diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php index 815428132..64758b0a7 100644 --- a/src/Operation/RenameCollection.php +++ b/src/Operation/RenameCollection.php @@ -18,6 +18,7 @@ namespace MongoDB\Operation; use MongoDB\Driver\Command; +use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException; use MongoDB\Driver\Server; use MongoDB\Driver\Session; use MongoDB\Driver\WriteConcern; diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php index a188ba774..9306a5312 100644 --- a/src/Operation/Watch.php +++ b/src/Operation/Watch.php @@ -36,6 +36,7 @@ use function array_intersect_key; use function array_key_exists; use function array_unshift; +use function assert; use function count; use function is_array; use function is_bool; @@ -85,7 +86,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber /** @var string */ private $databaseName; - /** @var integer|null */ + /** @var integer */ private $firstBatchSize; /** @var boolean */ @@ -282,7 +283,7 @@ final public function commandStarted(CommandStartedEvent $event): void return; } - $this->firstBatchSize = null; + $this->firstBatchSize = 0; $this->postBatchResumeToken = null; } @@ -325,7 +326,7 @@ public function execute(Server $server) { return new ChangeStream( $this->createChangeStreamIterator($server), - function ($resumeToken, $hasAdvanced) { + function ($resumeToken, $hasAdvanced): ChangeStreamIterator { return $this->resume($resumeToken, $hasAdvanced); } ); @@ -368,7 +369,10 @@ private function executeAggregate(Server $server): Cursor addSubscriber($this); try { - return $this->aggregate->execute($server); + $cursor = $this->aggregate->execute($server); + assert($cursor instanceof Cursor); + + return $cursor; } finally { removeSubscriber($this); } diff --git a/src/UpdateResult.php b/src/UpdateResult.php index de75afcbc..1fbbab600 100644 --- a/src/UpdateResult.php +++ b/src/UpdateResult.php @@ -43,7 +43,7 @@ public function __construct(WriteResult $writeResult) * This method should only be called if the write was acknowledged. * * @see UpdateResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getMatchedCount() @@ -82,7 +82,7 @@ public function getModifiedCount() * This method should only be called if the write was acknowledged. * * @see UpdateResult::isAcknowledged() - * @return integer + * @return integer|null * @throws BadMethodCallException is the write result is unacknowledged */ public function getUpsertedCount() diff --git a/src/functions.php b/src/functions.php index 042bee19f..dd2d94021 100644 --- a/src/functions.php +++ b/src/functions.php @@ -32,6 +32,7 @@ use ReflectionClass; use ReflectionException; +use function assert; use function end; use function get_object_vars; use function in_array; @@ -231,7 +232,7 @@ function is_pipeline($pipeline): bool reset($stage); $key = key($stage); - if (! isset($key[0]) || $key[0] !== '$') { + if (! is_string($key) || substr($key, 0, 1) !== '$') { return false; } } @@ -505,8 +506,9 @@ function extract_read_preference_from_options(array $options): ?ReadPreference function select_server(Manager $manager, array $options): Server { $session = extract_session_from_options($options); - if ($session instanceof Session && $session->getServer() !== null) { - return $session->getServer(); + $server = $session instanceof Session ? $session->getServer() : null; + if ($server !== null) { + return $server; } $readPreference = extract_read_preference_from_options($options); @@ -561,5 +563,7 @@ function select_server_for_aggregate_write_stage(Manager $manager, array &$optio throw $serverSelectionError; } + assert($server instanceof Server); + return $server; } From c5ac8e0df468064a149a315868441b6bec953309 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:24:51 +0300 Subject: [PATCH 200/321] PHPLIB-949: FLE - maxWireVersion should run on Mongo Server 4.0.x (#975) --- .../SpecTests/client-side-encryption/tests/maxWireVersion.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json b/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json index c1088a0ec..f04f58dff 100644 --- a/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json +++ b/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json @@ -1,7 +1,7 @@ { "runOn": [ { - "maxServerVersion": "4.0" + "maxServerVersion": "4.0.99" } ], "database_name": "default", From 3273248895f1dd1533ff995a3e447a19c1a4fa17 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Fri, 16 Sep 2022 14:29:04 +0300 Subject: [PATCH 201/321] PHPLIB-946: Forbid Serverless in Change Stream Disambiguated Unified Spec Tests (#974) --- .../change-streams/change-streams-disambiguatedPaths.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json b/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json index 9a639801e..91d8e66da 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json @@ -1,6 +1,6 @@ { "description": "disambiguatedPaths", - "schemaVersion": "1.3", + "schemaVersion": "1.4", "createEntities": [ { "client": { @@ -31,7 +31,8 @@ "sharded-replicaset", "load-balanced", "sharded" - ] + ], + "serverless": "forbid" } ], "initialData": [ From 153f61d0af7e521c317697bfa3aa82759965a6ce Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 16 Sep 2022 14:35:16 -0400 Subject: [PATCH 202/321] PHPLIB-920: Command monitoring and change stream examples (#976) --- examples/changestream.php | 58 +++++++++++++++++++++++++ examples/command_logger.php | 84 +++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 examples/changestream.php create mode 100644 examples/command_logger.php diff --git a/examples/changestream.php b/examples/changestream.php new file mode 100644 index 000000000..b897da4b2 --- /dev/null +++ b/examples/changestream.php @@ -0,0 +1,58 @@ +test->coll; +$collection->drop(); + +$changeStream = $collection->watch(); + +$documents = []; + +for ($i = 0; $i < 10; $i++) { + $documents[] = ['x' => $i]; +} + +$collection->insertMany($documents); + +$changeStream->rewind(); + +$startTime = time(); + +while (true) { + if ($changeStream->valid()) { + $event = $changeStream->current(); + assert(is_object($event)); + printf("%s\n", toJSON($event)); + } + + $changeStream->next(); + + if (time() - $startTime > 3) { + fprintf(STDERR, "Aborting after 3 seconds...\n"); + break; + } +} diff --git a/examples/command_logger.php b/examples/command_logger.php new file mode 100644 index 000000000..b987f6e19 --- /dev/null +++ b/examples/command_logger.php @@ -0,0 +1,84 @@ +getCommandName()); + + fprintf(STDERR, "command: %s\n", toJson($event->getCommand())); + fprintf(STDERR, "\n"); + } + + public function commandSucceeded(CommandSucceededEvent $event): void + { + fprintf(STDERR, "%s command succeeded\n", $event->getCommandName()); + fprintf(STDERR, "reply: %s\n", toJson($event->getReply())); + fprintf(STDERR, "\n"); + } + + public function commandFailed(CommandFailedEvent $event): void + { + fprintf(STDERR, "%s command failed\n", $event->getCommandName()); + fprintf(STDERR, "reply: %s\n", toJson($event->getReply())); + + $exception = $event->getError(); + fprintf(STDERR, "exception: %s\n", get_class($exception)); + fprintf(STDERR, "exception.code: %d\n", $exception->getCode()); + fprintf(STDERR, "exception.message: %s\n", $exception->getMessage()); + fprintf(STDERR, "\n"); + } +} + +$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); + +$client->getManager()->addSubscriber(new CommandLogger()); + +$collection = $client->test->coll; +$collection->drop(); + +$collection->insertMany([ + ['x' => 1], + ['x' => 2], + ['x' => 3], +]); + +$collection->updateMany( + ['x' => ['$gt' => 1]], + ['$set' => ['y' => 1]] +); + +$cursor = $collection->find([], ['batchSize' => 2]); + +foreach ($cursor as $document) { + assert(is_object($document)); + printf("%s\n", toJSON($document)); +} From 7a97f8edd72c0d5e39ac4183608430868fdc5cb7 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Mon, 26 Sep 2022 12:21:49 +0200 Subject: [PATCH 203/321] PHPLIB-982: Change evaluation of serverParameters to allow for server differences (#978) * PHPLIB-982: Change evaluation of serverParameters to allow for server differences * Fix topology typos --- tests/UnifiedSpecTests/RunOnRequirement.php | 10 +- .../ServerParameterHelper.php | 99 +++++++++++++++++++ tests/UnifiedSpecTests/UnifiedTestRunner.php | 29 ++---- 3 files changed, 113 insertions(+), 25 deletions(-) create mode 100644 tests/UnifiedSpecTests/ServerParameterHelper.php diff --git a/tests/UnifiedSpecTests/RunOnRequirement.php b/tests/UnifiedSpecTests/RunOnRequirement.php index d3d6d641f..4290bda9d 100644 --- a/tests/UnifiedSpecTests/RunOnRequirement.php +++ b/tests/UnifiedSpecTests/RunOnRequirement.php @@ -113,7 +113,7 @@ public function __construct(stdClass $o) } } - public function isSatisfied(string $serverVersion, string $topology, stdClass $serverParameters, bool $isAuthenticated, bool $isServerless, bool $isClientSideEncryptionSupported): bool + public function isSatisfied(string $serverVersion, string $topology, ServerParameterHelper $serverParameters, bool $isAuthenticated, bool $isServerless, bool $isClientSideEncryptionSupported): bool { if (isset($this->minServerVersion) && version_compare($serverVersion, $this->minServerVersion, '<')) { return false; @@ -128,9 +128,11 @@ public function isSatisfied(string $serverVersion, string $topology, stdClass $s } if (isset($this->serverParameters)) { - $constraint = new Matches($this->serverParameters, null, true, false); - if (! $constraint->evaluate($serverParameters, '', true)) { - return false; + foreach ($this->serverParameters as $parameter => $expectedValue) { + $constraint = new Matches($expectedValue, null, true, false); + if (! $constraint->evaluate($serverParameters->$parameter, '', true)) { + return false; + } } } diff --git a/tests/UnifiedSpecTests/ServerParameterHelper.php b/tests/UnifiedSpecTests/ServerParameterHelper.php new file mode 100644 index 000000000..6e14e8faa --- /dev/null +++ b/tests/UnifiedSpecTests/ServerParameterHelper.php @@ -0,0 +1,99 @@ + */ + private $parameters = []; + + /** @var bool */ + private $fetchAllParametersFailed = false; + + /** @var bool */ + private $allParametersFetched = false; + + public function __construct(Client $client) + { + $this->client = $client; + } + + /** @return mixed */ + public function __get(string $parameter) + { + if (! array_key_exists($parameter, $this->parameters)) { + $this->fetchParameter($parameter); + } + + return $this->parameters[$parameter]; + } + + private function fetchParameter(string $parameter): void + { + // Try fetching all parameters once + if (! $this->allParametersFetched && ! $this->fetchAllParametersFailed) { + $this->fetchAllParameters(); + } + + if (array_key_exists($parameter, $this->parameters)) { + return; + } + + // If fetching all parameters failed, or the parameter was not part of + // the list, fetch the single parameter as fallback + $this->fetchSingleParameter($parameter); + } + + private function fetchAllParameters(): void + { + try { + $database = $this->client->selectDatabase('admin'); + $cursor = $database->command( + ['getParameter' => '*'], + [ + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY), + 'typeMap' => [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ] + ); + + $this->parameters = $cursor->toArray()[0]; + $this->allParametersFetched = true; + } catch (CommandException $e) { + $this->fetchAllParametersFailed = true; + } + } + + private function fetchSingleParameter(string $parameter): void + { + $database = $this->client->selectDatabase('admin'); + $cursor = $database->command( + [ + 'getParameter' => 1, + $parameter => 1, + ], + [ + 'readPreference' => new ReadPreference(ReadPreference::PRIMARY), + 'typeMap' => [ + 'root' => 'array', + 'document' => 'array', + 'array' => 'array', + ], + ] + ); + + $this->parameters[$parameter] = $cursor->toArray()[0][$parameter]; + } +} diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 878797e16..008abe89c 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -84,6 +84,9 @@ final class UnifiedTestRunner /** @var FailPointObserver */ private $failPointObserver; + /** @var ServerParameterHelper */ + private $serverParameterHelper; + public function __construct(string $internalClientUri) { $this->internalClient = FunctionalTestCase::createTestClient($internalClientUri); @@ -95,6 +98,8 @@ public function __construct(string $internalClientUri) if ($this->isServerless() || strpos($internalClientUri, self::ATLAS_TLD) !== false) { $this->allowKillAllSessions = false; } + + $this->serverParameterHelper = new ServerParameterHelper($this->internalClient); } public function run(UnifiedTestCase $test): void @@ -248,7 +253,7 @@ private function checkRunOnRequirements(array $runOnRequirements): void $cachedIsSatisfiedArgs = [ $this->getServerVersion(), $this->getTopology(), - $this->getServerParameters(), + $this->serverParameterHelper, $this->isAuthenticated(), $this->isServerless(), $this->isClientSideEncryptionSupported(), @@ -264,7 +269,7 @@ private function checkRunOnRequirements(array $runOnRequirements): void // @todo Add server parameter requirements? Assert::markTestSkipped(sprintf( - 'Server (version=%s, toplogy=%s, auth=%s) does not meet test requirements', + 'Server (version=%s, topology=%s, auth=%s) does not meet test requirements', $cachedIsSatisfiedArgs[0], $cachedIsSatisfiedArgs[1], $cachedIsSatisfiedArgs[3] ? 'yes' : 'no' @@ -278,24 +283,6 @@ private function getPrimaryServer(): Server return $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY)); } - private function getServerParameters(): stdClass - { - $database = $this->internalClient->selectDatabase('admin'); - $cursor = $database->command( - ['getParameter' => '*'], - [ - 'readPreference' => new ReadPreference(ReadPreference::PRIMARY), - 'typeMap' => [ - 'root' => 'object', - 'document' => 'object', - 'array' => 'array', - ], - ] - ); - - return $cursor->toArray()[0]; - } - private function getServerVersion(): string { $database = $this->internalClient->selectDatabase('admin'); @@ -331,7 +318,7 @@ private function getTopology(): string return RunOnRequirement::TOPOLOGY_LOAD_BALANCED; default: - throw new UnexpectedValueException('Toplogy is neither single nor RS nor sharded'); + throw new UnexpectedValueException('Topology is neither single nor RS nor sharded'); } } From 0c7fede29af1b739c0aa6eebb840955d5220aeb4 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Mon, 26 Sep 2022 13:42:22 +0300 Subject: [PATCH 204/321] PHPLIB-948: Run unified tests from all specs against Atlas Serverless (#977) --- tests/UnifiedSpecTests/UnifiedSpecTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 9caf782dd..9a4fea23f 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -16,6 +16,7 @@ * Unified test format spec tests. * * @see https://github.com/mongodb/specifications/blob/master/source/unified-test-format/unified-test-format.rst + * @group serverless */ class UnifiedSpecTest extends FunctionalTestCase { @@ -33,9 +34,9 @@ class UnifiedSpecTest extends FunctionalTestCase 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: listIndexes pins the cursor to a connection' => 'PHPC does not implement CMAP', 'load-balancers/cursors are correctly pinned to connections for load-balanced clusters: change streams pin to a connection' => 'PHPC does not implement CMAP', 'load-balancers/monitoring events include correct fields: poolClearedEvent events include serviceId' => 'PHPC does not implement CMAP', - 'load-balancers/load-balancers/state change errors are correctly handled: only connections for a specific serviceId are closed when pools are cleared' => 'PHPC does not implement CMAP', 'load-balancers/state change errors are correctly handled: only connections for a specific serviceId are closed when pools are cleared' => 'PHPC does not implement CMAP', 'load-balancers/state change errors are correctly handled: errors during the initial connection hello are ignored' => 'PHPC does not implement CMAP', + 'load-balancers/state change errors are correctly handled: errors during authentication are processed' => 'PHPC does not implement CMAP', 'load-balancers/state change errors are correctly handled: stale errors are ignored' => 'PHPC does not implement CMAP', 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: all operations go to the same mongos' => 'PHPC does not implement CMAP', 'load-balancers/transactions are correctly pinned to connections for load-balanced clusters: transaction can be committed multiple times' => 'PHPC does not implement CMAP', @@ -141,7 +142,6 @@ public function provideCommandMonitoringTests() /** * @dataProvider provideCrudTests - * @group serverless */ public function testCrud(UnifiedTestCase $test): void { @@ -194,7 +194,6 @@ public function provideSessionsTests() /** * @dataProvider provideTransactionsTests - * @group serverless */ public function testTransactions(UnifiedTestCase $test): void { @@ -209,7 +208,6 @@ public function provideTransactionsTests() /** * @dataProvider provideVersionedApiTests * @group versioned-api - * @group serverless */ public function testVersionedApi(UnifiedTestCase $test): void { From d71588e1acd9c29afc132d0913f5bd05b29d9563 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Tue, 27 Sep 2022 13:44:58 +0300 Subject: [PATCH 205/321] PHPLIB-945: Update ChangeStreamEvent type definition to include clusterTime (#971) --- .../change-streams-clusterTime.json | 82 +++++++++++++++++++ .../change-streams-showExpandedEvents.json | 3 +- 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json b/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json new file mode 100644 index 000000000..55b4ae3fb --- /dev/null +++ b/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json @@ -0,0 +1,82 @@ +{ + "description": "change-streams-clusterTime", + "schemaVersion": "1.4", + "createEntities": [ + { + "client": { + "id": "client0", + "useMultipleMongoses": false + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "database0" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "collection0" + } + } + ], + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "topologies": [ + "replicaset", + "sharded-replicaset", + "load-balanced", + "sharded" + ], + "serverless": "forbid" + } + ], + "initialData": [ + { + "collectionName": "collection0", + "databaseName": "database0", + "documents": [] + } + ], + "tests": [ + { + "description": "clusterTime is present", + "operations": [ + { + "name": "createChangeStream", + "object": "collection0", + "arguments": { + "pipeline": [] + }, + "saveResultAsEntity": "changeStream0" + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + } + }, + { + "name": "iterateUntilDocumentOrError", + "object": "changeStream0", + "expectResult": { + "ns": { + "db": "database0", + "coll": "collection0" + }, + "clusterTime": { + "$$exists": true + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json index 3eed2f534..a59a81849 100644 --- a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json +++ b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json @@ -8,7 +8,8 @@ "replicaset", "sharded-replicaset", "sharded" - ] + ], + "serverless": "forbid" } ], "createEntities": [ From 248e4e59d967f5ce7da3564ae3e792c318ba551e Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 28 Sep 2022 08:07:56 +0200 Subject: [PATCH 206/321] PHPLIB-979: Run checks on example code (#980) --- phpcs.xml.dist | 1 + psalm.xml.dist | 1 + 2 files changed, 2 insertions(+) diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 639bfcdf5..546988605 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -10,6 +10,7 @@ src + examples tests diff --git a/psalm.xml.dist b/psalm.xml.dist index 8cf6c4435..5a922b4ca 100644 --- a/psalm.xml.dist +++ b/psalm.xml.dist @@ -9,6 +9,7 @@ > + From 3a9c15e9a9ff907c46a5d0bf44120dc82e2716a0 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 28 Sep 2022 08:35:15 +0200 Subject: [PATCH 207/321] PHPLIB-596: Add tutorial for connecting to MongoDB (#979) * PHPLIB-596: Add tutorial for connecting to MongoDB * Fix formatting breaking TOC Co-authored-by: Jeremy Mikola * Link connecting tutorial on tutorials page Co-authored-by: Jeremy Mikola --- docs/index.txt | 2 ++ .../method/MongoDBClient__construct.txt | 23 ++++++++++++++--- docs/tutorial.txt | 1 + docs/tutorial/connecting.txt | 25 +++++++++++++++++++ 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 docs/tutorial/connecting.txt diff --git a/docs/index.txt b/docs/index.txt index 8c167eb63..ae9da18a8 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -27,6 +27,8 @@ following pages should help you get started: - :doc:`/tutorial/install-php-library` +- :doc:`/tutorial/connecting` + - :doc:`/tutorial/crud` - :doc:`/tutorial/commands` diff --git a/docs/reference/method/MongoDBClient__construct.txt b/docs/reference/method/MongoDBClient__construct.txt index 091ae6144..0b89b6906 100644 --- a/docs/reference/method/MongoDBClient__construct.txt +++ b/docs/reference/method/MongoDBClient__construct.txt @@ -49,12 +49,27 @@ initialized on demand, when the first operation is executed. Examples -------- +.. start-connecting-include + +Connecting to a Standalone server +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you do not specify a ``$uri`` value, the driver connects to a standalone +:program:`mongod` on ``127.0.0.1`` via port ``27017``. To connect to a different +server, pass the corresponding connection string as the first parameter when +creating the :phpclass:`Client ` instance: + +.. code-block:: php + + ` documentation. +.. end-connecting-include + Specifying a Custom Type Map ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/tutorial.txt b/docs/tutorial.txt index cca3ee345..e28bcf4c5 100644 --- a/docs/tutorial.txt +++ b/docs/tutorial.txt @@ -5,6 +5,7 @@ Tutorials .. toctree:: + /tutorial/connecting /tutorial/crud /tutorial/collation /tutorial/commands diff --git a/docs/tutorial/connecting.txt b/docs/tutorial/connecting.txt new file mode 100644 index 000000000..c964362a0 --- /dev/null +++ b/docs/tutorial/connecting.txt @@ -0,0 +1,25 @@ +===================== +Connecting to MongoDB +===================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Creating a Client instance +-------------------------------------------------------- + +.. include:: /reference/method/MongoDBClient__construct.txt + :start-after: start-connecting-include + :end-before: end-connecting-include + +Specifying connection options +----------------------------- + +Connection options can be passed via the ``$uri`` parameter, or through the +``$options`` and ``$driverOptions`` parameters. The available options are +documented in the :phpmethod:`MongoDB\\Client::__construct()` reference. From b5365c80bc8522340c848d135b8ed9a02fc6d710 Mon Sep 17 00:00:00 2001 From: levon80999 <70570610+levon80999@users.noreply.github.com> Date: Fri, 30 Sep 2022 15:34:46 +0300 Subject: [PATCH 208/321] PHPLIB-638: Ensure writeConcernError is reported for findAndModify (#983) --- .../Operation/FindAndModifyFunctionalTest.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index b9b6b605c..e8d837c2b 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -3,6 +3,7 @@ namespace MongoDB\Tests\Operation; use MongoDB\Driver\BulkWrite; +use MongoDB\Driver\Exception\CommandException; use MongoDB\Driver\ReadPreference; use MongoDB\Driver\WriteConcern; use MongoDB\Exception\UnsupportedException; @@ -92,6 +93,25 @@ public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSide $operation->execute($this->getPrimaryServer()); } + public function testFindAndModifyReportedWriteConcernError(): void + { + if (($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets()) || ! $this->isReplicaSet()) { + $this->markTestSkipped('Test only applies to replica sets'); + } + + $this->expectException(CommandException::class); + $this->expectExceptionCode(100); + $this->expectExceptionMessageMatches('/Write Concern error:/'); + + $operation = new FindAndModify( + $this->getDatabaseName(), + $this->getCollectionName(), + ['remove' => true, 'writeConcern' => new WriteConcern(50)] + ); + + $operation->execute($this->getPrimaryServer()); + } + public function testSessionOption(): void { (new CommandObserver())->observe( From c8f118872c95cd37e7643f63c59db8856ab3d30a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 30 Sep 2022 11:58:13 -0400 Subject: [PATCH 209/321] PHPLIB-790: Docs for common troubleshooting issues (#982) * Clarify how batchSize option applies to aggregate and getMore * FAQ for common extension install errors * Server selection tutorial and FAQ entry * PHPLIB-937: Clarify install steps when not using Composer * Fix indentation for list in GridFS tutorial --- docs/faq.txt | 135 ++++++++++++ docs/includes/apiargs-aggregate-option.yaml | 11 +- .../includes/apiargs-method-watch-option.yaml | 13 +- docs/index.txt | 1 + docs/tutorial.txt | 1 + docs/tutorial/gridfs.txt | 16 +- docs/tutorial/install-php-library.txt | 47 ++--- docs/tutorial/server-selection.txt | 192 ++++++++++++++++++ 8 files changed, 376 insertions(+), 40 deletions(-) create mode 100644 docs/faq.txt create mode 100644 docs/tutorial/server-selection.txt diff --git a/docs/faq.txt b/docs/faq.txt new file mode 100644 index 000000000..ec541a820 --- /dev/null +++ b/docs/faq.txt @@ -0,0 +1,135 @@ +========================== +Frequently Asked Questions +========================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Common Extension Installation Errors +------------------------------------ + +PHP Headers Not Found +~~~~~~~~~~~~~~~~~~~~~ + +For example: + +.. code-block:: none + + /private/tmp/pear/install/mongodb/php_phongo.c:24:10: fatal error: 'php.h' file not found + + #include + ^~~~~~~ + +This error indicates that PHP's build system cannot find the necessary headers. +All PHP extensions require headers in order to compile. Additionally, those +headers must correspond to the PHP runtime for which the extension will be used. +Generally, the ``phpize`` command (invoked by ``pecl``) will ensure that the +extension builds with the correct headers. + +Note that the mere presence of a PHP runtime does not mean that headers are +available. On various Linux distributions, headers are often published under a +separate ``php-dev`` or ``php-devel`` package. On macOS, the default PHP runtime +does not include headers and users typically need to install PHP (and headers) +via `Homebrew `_ in order to build an extension. + +Multiple PHP Runtimes Installed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If your system has multiple versions of PHP installed, each version will have +its own ``pecl`` and ``phpize`` commands. Additionally, each PHP runtime may +have separate ``php.ini`` files for each SAPI (e.g. FPM, CLI). If the extension +has been installed but is not available at runtime, double-check that you have +used the correct ``pecl`` command and have modified the appropriate ``php.ini`` +file(s). + +If there is any doubt about the ``php.ini`` file being used by a PHP runtime, +you should examine the output of :php:`phpinfo() ` for that particular +SAPI. Additionally, :php:`php_ini_loaded_file() ` and +:php:`php_ini_scanned_files() ` may be used to determine +exactly which INI files have been loaded by PHP. + +Loading an Incompatible DLL on Windows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +PECL builds Windows binaries for various combinations of PHP version, +thread-safety (TS or NTS), and architecture (x86 or x64). Failure to select the +correct binary will result in an error when attempting to load the extension DLL +at runtime: + +.. code-block:: none + + PHP Warning: PHP Startup: Unable to load dynamic library 'mongodb' + +Ensure that you have downloaded a DLL that corresponds to the following PHP +runtime properties: + +- PHP version (``PHP_VERSION``) +- Thread-safety (``PHP_ZTS``) +- Architecture (``PHP_INT_SIZE``) + +In addition to the aforementioned constants, these properties can also be +inferred from :php:`phpinfo() `. If your system has multiple PHP +runtimes installed, double-check that you are examining the ``phpinfo()`` output +for the correct environment. + +Server Selection Failures +------------------------- + +The follow are all examples of +:doc:`Server Selection ` failures: + +.. code-block:: none + + No suitable servers found (`serverSelectionTryOnce` set): + [connection refused calling hello on 'a.example.com:27017'] + [connection refused calling hello on 'b.example.com:27017'] + + No suitable servers found: `serverSelectionTimeoutMS` expired: + [socket timeout calling hello on 'example.com:27017'] + + No suitable servers found: `serverSelectionTimeoutMS` expired: + [connection timeout calling hello on 'a.example.com:27017'] + [connection timeout calling hello on 'b.example.com:27017'] + [TLS handshake failed: -9806 calling hello on 'c.example.com:27017'] + + No suitable servers found: `serverselectiontimeoutms` timed out: + [TLS handshake failed: certificate verify failed (64): IP address mismatch calling hello on 'a.example.com:27017'] + [TLS handshake failed: certificate verify failed (64): IP address mismatch calling hello on 'b.example.com:27017'] + +These errors typically manifest as a +:php:`MongoDB\\Driver\\Exception\\ConnectionTimeoutException ` +exception from the driver. The actual exception messages originate from +libmongoc, which is the underlying library used by the PHP driver. Since these +messages can take many forms, it's helpful to break down the structure of the +message so you can better diagnose errors in your application. + +Messages will typically start with "No suitable servers found". The next part of +the message indicates *how* server selection failed. By default, the PHP driver +avoids a server selection loop and instead makes a single attempt (according to +the ``serverSelectionTryOnce`` connection string option). If the driver is +configured to utilize a loop, a message like "serverSelectionTimeoutMS expired" +will tell us that we exhausted its time limit. + +The last component of the message tells us *why* server selection failed, and +includes one or more errors directly from the topology scanner, which is the +service responsible for connecting to and monitoring each host. Any host that +last experienced an error during monitoring will be included in this list. These +messages typically originate from low-level socket or TLS functions. + +The following is not meant to be exhaustive, but will hopefully point you in the +right direction for analyzing the contributing factor(s) for a server selection +failure: + +- "connection refused" likely indicates that the remote host is not listening on + the expected port. +- "connection timeout" could indicate a routing or firewall issue, or perhaps + a timeout due to latency. +- "socket timeout" suggests that a connection *was* established at some point + but was dropped or otherwise timeout out due to latency. +- "TLS handshake failed" suggests something related to TLS or OCSP verification + and is sometimes indicative of misconfigured TLS certificates. diff --git a/docs/includes/apiargs-aggregate-option.yaml b/docs/includes/apiargs-aggregate-option.yaml index c75880df2..e5b410c4f 100644 --- a/docs/includes/apiargs-aggregate-option.yaml +++ b/docs/includes/apiargs-aggregate-option.yaml @@ -12,9 +12,14 @@ arg_name: option name: batchSize type: integer description: | - Specifies the initial batch size for the cursor. A batchSize of ``0`` means an - empty first batch and is useful for quickly returning a cursor or failure - message without doing significant server-side work. + Specifies the batch size for the cursor, which will apply to both the initial + ``aggregate`` command and any subsequent ``getMore`` commands. This determines + the maximum number of documents to return in each response from the server. + + A batchSize of ``0`` is special in that and will only apply to the initial + ``aggregate`` command; subsequent ``getMore`` commands will use the server's + default batch size. This may be useful for quickly returning a cursor or + failure from ``aggregate`` without doing significant server-side work. interface: phpmethod operation: ~ optional: true diff --git a/docs/includes/apiargs-method-watch-option.yaml b/docs/includes/apiargs-method-watch-option.yaml index 1aa1de2b2..d09278286 100644 --- a/docs/includes/apiargs-method-watch-option.yaml +++ b/docs/includes/apiargs-method-watch-option.yaml @@ -3,8 +3,17 @@ arg_name: option name: batchSize type: integer description: | - Specifies the maximum number of change events to return in each batch of the - response from the MongoDB cluster. + Specifies the batch size for the cursor, which will apply to both the initial + ``aggregate`` command and any subsequent ``getMore`` commands. This determines + the maximum number of change events to return in each response from the + server. + + .. note:: + + Irrespective of the ``batchSize`` option, the initial ``aggregate`` command + response for a change stream generally does not include any documents + unless another option is used to configure its starting point (e.g. + ``startAfter``). interface: phpmethod operation: ~ optional: true diff --git a/docs/index.txt b/docs/index.txt index ae9da18a8..20045f524 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -66,3 +66,4 @@ encounter in the library documentation: /tutorial /upgrade /reference + FAQ diff --git a/docs/tutorial.txt b/docs/tutorial.txt index e28bcf4c5..a749af2d1 100644 --- a/docs/tutorial.txt +++ b/docs/tutorial.txt @@ -6,6 +6,7 @@ Tutorials .. toctree:: /tutorial/connecting + /tutorial/server-selection /tutorial/crud /tutorial/collation /tutorial/commands diff --git a/docs/tutorial/gridfs.txt b/docs/tutorial/gridfs.txt index ba9b83681..81f6d2639 100644 --- a/docs/tutorial/gridfs.txt +++ b/docs/tutorial/gridfs.txt @@ -28,14 +28,14 @@ method. The bucket can be constructed with various options: - - ``bucketName`` determines the prefix for the bucket's metadata and chunk - collections. The default value is ``"fs"``. - - ``chunkSizeBytes`` determines the size of each chunk. GridFS divides the - file into chunks of this length, except for the last, which is only as large - as needed. The default size is ``261120`` (i.e. 255 KiB). - - ``readConcern``, ``readPreference`` and ``writeConcern`` options can be used - to specify defaults for read and write operations, much like the - :phpclass:`MongoDB\\GridFS\\Collection` options. +- ``bucketName`` determines the prefix for the bucket's metadata and chunk + collections. The default value is ``"fs"``. +- ``chunkSizeBytes`` determines the size of each chunk. GridFS divides the file + into chunks of this length, except for the last, which is only as large as + needed. The default size is ``261120`` (i.e. 255 KiB). +- ``readConcern``, ``readPreference`` and ``writeConcern`` options can be used + to specify defaults for read and write operations, much like the + :phpclass:`MongoDB\\GridFS\\Collection` options. Uploading Files with Writable Streams ------------------------------------- diff --git a/docs/tutorial/install-php-library.txt b/docs/tutorial/install-php-library.txt index acaa8ed10..f4087cba0 100644 --- a/docs/tutorial/install-php-library.txt +++ b/docs/tutorial/install-php-library.txt @@ -50,24 +50,15 @@ your ``php.ini`` file: extension=php_mongodb.dll -Windows binaries are available for various combinations of PHP version, -thread-safety, and architecture. Failure to select the correct binary will -result in an error attempting to load the extension DLL at runtime. Additional -considerations for Windows are discussed in the +Additional considerations for Windows are discussed in the :php:`Windows installation documentation `. -.. note:: - - If your system has multiple versions of PHP installed, each version will have - its own ``pecl`` command and ``php.ini`` file. Additionally, PHP may also use - separate ``php.ini`` files for its web and CLI environments. If the extension - has been installed but is not available at runtime, double-check that you - have used the correct ``pecl`` command (or binary in the case of Windows) and - have modified the appropriate ``php.ini`` file(s). - Installing the Library ---------------------- +Using Composer +~~~~~~~~~~~~~~ + The preferred method of installing the |php-library| is with `Composer `_ by running the following command from your project root: @@ -76,13 +67,6 @@ your project root: composer require mongodb/mongodb -While not recommended, you may also manually install the library using a source -archive attached to the -`GitHub releases `_. - -Configure Autoloading -~~~~~~~~~~~~~~~~~~~~~ - Once you have installed the library, ensure that your application includes Composer's autoloader as in the following example: @@ -96,11 +80,20 @@ Refer to Composer's `autoloading documentation `_ for more information about setting up autoloading. -If you installed the library manually from a source archive, you will need to -manually configure autoloading: - -#. Map the top-level ``MongoDB\`` namespace to the ``src/`` directory - using your preferred autoloader implementation. +Manual Installation Without Composer +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#. Manually require the ``src/functions.php`` file. This is necessary because - PHP does not support autoloading for functions. +While not recommended, you may also manually install the library using a source +archive attached to the +`GitHub releases `_. When +installing the library without Composer, you must ensure that all library +classes *and* functions are loaded for your application: + +#. If you are using a `PSR-4 `_ autoloader, + map the top-level ``MongoDB\`` namespace to the ``src/`` directory. If you + are not using an autoloader, manually require _all_ class files found + recursively within the ``src/`` directory. + +#. Regardless of whether you are using an autoloader, manually require the + ``src/functions.php`` file. This is necessary because PHP does not support + autoloading for functions. diff --git a/docs/tutorial/server-selection.txt b/docs/tutorial/server-selection.txt new file mode 100644 index 000000000..31047d936 --- /dev/null +++ b/docs/tutorial/server-selection.txt @@ -0,0 +1,192 @@ +=============================== +Server Selection and Monitoring +=============================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Server Selection and Monitoring +------------------------------- + +Before any operation can be executed, the |php-library| must first select a +server from the topology (e.g. replica set, sharded cluster). Selecting a server +requires an accurate view of the topology, so the driver (i.e. ``mongodb`` +extension) regularly monitors the servers to which it is connected. + +In most other drivers, server discovery and monitoring is handled by a +background thread; however, the PHP driver is single-threaded and must therefore +perform monitoring *between* operations initiated by the application. + +Consider the following example application: + +.. code-block:: php + + test; + + /** + * The library creates an internal object for this operation and must select + * a server to use for executing that operation. + * + * If this is the first operation on the underlying libmongoc client, it must + * first discover the topology. It does so by establishing connections to any + * host(s) in the seed list (this may entail TLS and OCSP verification) and + * issuing "hello" commands. + * + * In the case of a replica set, connecting to a single host in the seed list + * should allow the driver to discover all other members in the replica set. + * In the case of a sharded cluster, the driver will start with an initial + * seed list of mongos hosts and, if SRV polling is utilized, may discover + * additional mongos hosts over time. + * + * If the topology was already initialized (i.e. this is not the first + * operation on the client), the driver may still need to perform monitoring + * (i.e. "hello" commands) and refresh its view of the topology. This process + * may entail adding or removing hosts from the topology. + * + * Once the topology has been discovered and any necessary monitoring has + * been performed, the driver may select a server according to the rules + * outlined in the server selection specification (e.g. applying a read + * preference, filtering hosts by latency). + */ + $database->command(['ping' => 1]); + +Although the application consists of only a few lines of PHP, there is actually +quite a lot going on behind the scenes! Interested readers can find this process +discussed in greater detail in the following documents: + +- `Single-threaded Mode `_ in the libmongoc documentation +- `Server Discovery and Monitoring `_ specification +- `Server Selection `_ specification + +Connection String Options +------------------------- + +There are several connection string options relevant to server selection and +monitoring. + +connectTimeoutMS +~~~~~~~~~~~~~~~~ + +``connectTimeoutMS`` specifies the limit for both establishing a connection to +a server *and* the socket timeout for server monitoring (``hello`` commands). +This defaults to 10 seconds for single-threaded drivers such as PHP. + +When a server times out during monitoring, it will not be re-checked until at +least five seconds +(`cooldownMS `_) +have elapsed. This timeout is intended to avoid having single-threaded drivers +block for ``connectTimeoutMS`` on *each* subsequent scan after an error. + +Applications can consider setting this option to slightly more than the greatest +latency among servers in the cluster. For example, if the greatest ``ping`` time +between the PHP application server and a database server is 200ms, it may be +reasonable to specify a timeout of one second. This would allow ample time for +establishing a connection and monitoring an accessible server, while also +significantly reducing the time to detect an inaccessible server. + +heartbeatFrequencyMS +~~~~~~~~~~~~~~~~~~~~ + +``heartbeatFrequencyMS`` determines how often monitoring should occur. This +defaults to 60 seconds for single-threaded drivers and can be set as low as +500ms. + +serverSelectionTimeoutMS +~~~~~~~~~~~~~~~~~~~~~~~~ + +``serverSelectionTimeoutMS`` determines the maximum amount of time to spend in +the server selection loop. This defaults to 30 seconds, but applications will +typically fail sooner if ``serverSelectionTryOnce`` is ``true`` and a smaller +``connectTimeoutMS`` value is in effect. + +The original default was established at a time when replica set elections took +much longer to complete. Applications can consider setting this option to +slightly more than the expected completion time for an election. For example, +:manual:`Replica Set Elections ` states that +elections will not typically exceed 12 seconds, so a 15-second timeout may be +reasonable. Applications connecting to a sharded cluster may consider a smaller +value still, since ``mongos`` insulates the driver from elections. + +That said, ``serverSelectionTimeoutMS`` should generally not be set to a value +smaller than ``connectTimeoutMS``. + +serverSelectionTryOnce +~~~~~~~~~~~~~~~~~~~~~~ + +``serverSelectionTryOnce`` determines whether the driver should give up after +the first failed server selection attempt or continue waiting until +``serverSelectionTimeoutMS`` is reached. PHP defaults to ``true``, which allows +the driver to "fail fast" when a server cannot be selected (e.g. no primary +during a failover). + +The default behavior is generally desirable for a high-traffic web applications, +as it means the worker process will not be blocked in a server selection loop +and can instead return an error response and immediately go on to serve another +request. Additionally, other driver features such as retryable reads and writes +can still enable applications to avoid transient errors such as a failover. + +That said, applications that prioritize resiliency over response time (and +worker pool utilization) may want to specify ``false`` for +``serverSelectionTryOnce``. + +socketCheckIntervalMS +~~~~~~~~~~~~~~~~~~~~~ + +``socketCheckIntervalMS`` determines how often a socket should be checked (using +a ``ping`` command) if it has not been used recently. This defaults to 5 seconds +and is intentionally lower than ``heartbeatFrequencyMS`` to better allow +single-threaded drivers to recover dropped connections. + +socketTimeoutMS +~~~~~~~~~~~~~~~ + +``socketTimeoutMS`` determines the maximum amount of time to spend reading or +writing to a socket. Since server monitoring uses ``connectTimeoutMS`` for its +socket timeouts, ``socketTimeoutMS`` only applies to operations executed by the +application. + +``socketTimeoutMS`` defaults to 5 minutes; however, it's likely that a PHP web +request would be terminated sooner due to +`max_execution_time `_, +which defaults to 30 seconds for web SAPIs. In a CLI environment, where +``max_execution_time`` is unlimited by default, it is more likely that +``socketTimeoutMS`` could be reached. + +.. note:: + + ``socketTimeoutMS`` is not directly related to server selection and + monitoring; however, it is frequently associated with the other options and + therefore bears mentioning. From 356b89c6639bb95d2573bf94e169d6b603a2b595 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 4 Oct 2022 00:41:04 -0400 Subject: [PATCH 210/321] Note name of error code literal in findAndModify WC test (#984) --- tests/Operation/FindAndModifyFunctionalTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php index e8d837c2b..bc89fb524 100644 --- a/tests/Operation/FindAndModifyFunctionalTest.php +++ b/tests/Operation/FindAndModifyFunctionalTest.php @@ -100,7 +100,7 @@ public function testFindAndModifyReportedWriteConcernError(): void } $this->expectException(CommandException::class); - $this->expectExceptionCode(100); + $this->expectExceptionCode(100 /* UnsatisfiableWriteConcern */); $this->expectExceptionMessageMatches('/Write Concern error:/'); $operation = new FindAndModify( From 8a327525dbb4a2a9bceac62bfc027e88309db756 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 4 Oct 2022 08:37:35 +0200 Subject: [PATCH 211/321] PHPLIB-987: Add more examples (#981) * Fix include path for autoload file * Add examples for bulk writes and with_transaction * Add aggregation example * Add example for persistable objects * Ignore certain phpcs errors for all examples * Add example for deserialisation using typemap * Remove unnecessary batchSize option * Use __DIR__ instead of dirname(__FILE__) * Fix capitalisation for TypeMap * Simplify persistable example models * Add note about replica set requirements * Add note about examples to the documentation --- docs/index.txt | 2 + examples/aggregate.php | 58 ++++++++++++++++ examples/bulk.php | 78 ++++++++++++++++++++++ examples/changestream.php | 5 +- examples/command_logger.php | 5 +- examples/persistable.php | 109 ++++++++++++++++++++++++++++++ examples/typemap.php | 120 ++++++++++++++++++++++++++++++++++ examples/with_transaction.php | 56 ++++++++++++++++ phpcs.xml.dist | 4 ++ psalm-baseline.xml | 9 +++ 10 files changed, 441 insertions(+), 5 deletions(-) create mode 100644 examples/aggregate.php create mode 100644 examples/bulk.php create mode 100644 examples/persistable.php create mode 100644 examples/typemap.php create mode 100644 examples/with_transaction.php diff --git a/docs/index.txt b/docs/index.txt index 20045f524..77890982c 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -37,6 +37,8 @@ following pages should help you get started: - :doc:`/reference/bson` +Code examples can be found in the ``examples`` directory in the source code. + If you have previously worked with the legacy ``mongo`` extension, it will be helpful to review the :doc:`/upgrade` for a summary of API changes between the old driver and this library. diff --git a/examples/aggregate.php b/examples/aggregate.php new file mode 100644 index 000000000..9a4873593 --- /dev/null +++ b/examples/aggregate.php @@ -0,0 +1,58 @@ +test->coll; +$collection->drop(); + +$documents = []; + +for ($i = 0; $i < 100; $i++) { + $documents[] = ['randomValue' => rand(0, 1000)]; +} + +$collection->insertMany($documents); + +$pipeline = [ + [ + '$group' => [ + '_id' => null, + 'totalCount' => ['$sum' => 1], + 'evenCount' => [ + '$sum' => ['$mod' => ['$randomValue', 2]], + ], + 'oddCount' => [ + '$sum' => ['$subtract' => [1, ['$mod' => ['$randomValue', 2]]]], + ], + 'maxValue' => ['$max' => '$randomValue'], + 'minValue' => ['$min' => '$randomValue'], + ], + ], +]; + +$cursor = $collection->aggregate($pipeline); + +foreach ($cursor as $document) { + assert(is_object($document)); + printf("%s\n", toJSON($document)); +} diff --git a/examples/bulk.php b/examples/bulk.php new file mode 100644 index 000000000..1af53f755 --- /dev/null +++ b/examples/bulk.php @@ -0,0 +1,78 @@ +test->coll; +$collection->drop(); + +$documents = []; + +for ($i = 0; $i < 10; $i++) { + $documents[] = ['x' => $i]; +} + +$collection->insertMany($documents); + +$collection->bulkWrite( + [ + [ + 'deleteMany' => [ + ['x' => ['$gt' => 7]], // Filter + ], + ], + [ + 'deleteOne' => [ + ['x' => 4], // Filter + ], + ], + [ + 'replaceOne' => [ + ['x' => 1], // Filter + ['y' => 1], // Replacement + ], + ], + [ + 'updateMany' => [ + ['x' => ['$gt' => 5]], // Filter + ['$set' => ['updateMany' => true]], // Update + ], + ], + [ + 'updateOne' => [ + ['x' => 2], // Filter + ['$set' => ['y' => 2]], // Update + ], + ], + [ + 'insertOne' => [ + ['x' => 10], // Document + ], + ], + ] +); + +$cursor = $collection->find([]); + +foreach ($cursor as $document) { + assert(is_object($document)); + printf("%s\n", toJSON($document)); +} diff --git a/examples/changestream.php b/examples/changestream.php index b897da4b2..b54be8ff2 100644 --- a/examples/changestream.php +++ b/examples/changestream.php @@ -3,8 +3,6 @@ namespace MongoDB\Examples; -require '../vendor/autoload.php'; - use MongoDB\Client; use function assert; @@ -18,11 +16,14 @@ use const STDERR; +require __DIR__ . '/../vendor/autoload.php'; + function toJSON(object $document): string { return toRelaxedExtendedJSON(fromPHP($document)); } +// Change streams require a replica set or sharded cluster $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); $collection = $client->test->coll; diff --git a/examples/command_logger.php b/examples/command_logger.php index b987f6e19..7eab169bf 100644 --- a/examples/command_logger.php +++ b/examples/command_logger.php @@ -3,8 +3,6 @@ namespace MongoDB\Examples; -require '../vendor/autoload.php'; - use MongoDB\Client; use MongoDB\Driver\Monitoring\CommandFailedEvent; use MongoDB\Driver\Monitoring\CommandStartedEvent; @@ -22,12 +20,13 @@ use const STDERR; +require __DIR__ . '/../vendor/autoload.php'; + function toJSON(object $document): string { return toRelaxedExtendedJSON(fromPHP($document)); } -// phpcs:disable Squiz.Classes.ClassFileName.NoMatch class CommandLogger implements CommandSubscriber { public function commandStarted(CommandStartedEvent $event): void diff --git a/examples/persistable.php b/examples/persistable.php new file mode 100644 index 000000000..f41cc54b3 --- /dev/null +++ b/examples/persistable.php @@ -0,0 +1,109 @@ + */ + public $emails = []; + + public function __construct(string $name) + { + $this->id = new ObjectId(); + $this->name = $name; + } + + public function getId(): ObjectId + { + return $this->id; + } + + public function bsonSerialize(): object + { + return (object) [ + '_id' => $this->id, + 'name' => $this->name, + 'emails' => $this->emails, + ]; + } + + public function bsonUnserialize(array $data): void + { + if (! $data['_id'] instanceof ObjectId) { + throw new UnexpectedValueException('_id field is not of the expected type'); + } + + if (! $data['emails'] instanceof BSONArray) { + throw new UnexpectedValueException('emails field is not of the expected type'); + } + + $this->id = $data['_id']; + $this->name = (string) $data['name']; + + /** @psalm-suppress MixedPropertyTypeCoercion */ + $this->emails = $data['emails']->getArrayCopy(); // Emails will be passed as a BSONArray instance + } +} + +class PersistableEmail implements Persistable +{ + /** @var string */ + public $type; + + /** @var string */ + public $address; + + public function __construct(string $type, string $address) + { + $this->type = $type; + $this->address = $address; + } + + public function bsonSerialize(): object + { + return (object) [ + 'type' => $this->type, + 'address' => $this->address, + ]; + } + + public function bsonUnserialize(array $data): void + { + $this->type = (string) $data['type']; + $this->address = (string) $data['address']; + } +} + +$entry = new PersistableEntry('alcaeus'); +$entry->emails[] = new PersistableEmail('work', 'alcaeus@example.com'); +$entry->emails[] = new PersistableEmail('private', 'secret@example.com'); + +$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); + +$collection = $client->test->coll; +$collection->drop(); + +$collection->insertOne($entry); + +$foundEntry = $collection->findOne([]); + +/** @psalm-suppress ForbiddenCode */ +var_dump($foundEntry); diff --git a/examples/typemap.php b/examples/typemap.php new file mode 100644 index 000000000..02d222e01 --- /dev/null +++ b/examples/typemap.php @@ -0,0 +1,120 @@ + */ + private $emails; + + private function __construct() + { + } + + public function getId(): ObjectId + { + return $this->id; + } + + public function getName(): string + { + return $this->name; + } + + public function getEmails(): array + { + return $this->emails; + } + + public function bsonUnserialize(array $data): void + { + if (! $data['_id'] instanceof ObjectId) { + throw new UnexpectedValueException('_id field is not of the expected type'); + } + + if (! is_array($data['emails'])) { + throw new UnexpectedValueException('emails field is not of the expected type'); + } + + $this->id = $data['_id']; + $this->name = (string) $data['name']; + + /** @psalm-suppress MixedPropertyTypeCoercion */ + $this->emails = $data['emails']; + } +} + +class TypeMapEmail implements Unserializable +{ + /** @var string */ + private $type; + + /** @var string */ + private $address; + + private function __construct() + { + } + + public function getType(): string + { + return $this->type; + } + + public function getAddress(): string + { + return $this->address; + } + + public function bsonUnserialize(array $data): void + { + $this->type = (string) $data['type']; + $this->address = (string) $data['address']; + } +} + +$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); + +$collection = $client->test->coll; +$collection->drop(); + +$document = [ + 'name' => 'alcaeus', + 'emails' => [ + ['type' => 'work', 'address' => 'alcaeus@example.com'], + ['type' => 'private', 'address' => 'secret@example.com'], + ], +]; + +$collection->insertOne($document); + +$typeMap = [ + 'root' => TypeMapEntry::class, // Root object will be an Entry instance + 'fieldPaths' => [ + 'emails' => 'array', // Emails field is used as PHP array + 'emails.$' => TypeMapEmail::class, // Each element in the emails array will be an Email instance + ], +]; + +$entry = $collection->findOne([], ['typeMap' => $typeMap]); + +/** @psalm-suppress ForbiddenCode */ +var_dump($entry); diff --git a/examples/with_transaction.php b/examples/with_transaction.php new file mode 100644 index 000000000..a30a9ab2b --- /dev/null +++ b/examples/with_transaction.php @@ -0,0 +1,56 @@ += 4.0) or sharded cluster (MongoDB >= 4.2) +$client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); + +$collection = $client->test->coll; +$collection->drop(); + +$insertData = function (Session $session) use ($collection): void { + $collection->insertMany( + [ + ['x' => 1], + ['x' => 2], + ['x' => 3], + ], + ['session' => $session] + ); + + $collection->updateMany( + ['x' => ['$gt' => 1]], + ['$set' => ['y' => 1]], + ['session' => $session] + ); +}; + +$session = $client->startSession(); + +with_transaction($session, $insertData); + +$cursor = $collection->find([]); + +foreach ($cursor as $document) { + assert(is_object($document)); + printf("%s\n", toJSON($document)); +} diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 546988605..7db7074b7 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -176,6 +176,10 @@ /tests/GridFS/UnusableStream.php + /examples /tests/PHPUnit/ConstraintTrait.php + + /examples + diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 952117897..179ce8c12 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,14 @@ + + + $address + $emails + $id + $name + $type + + $driverOptions['driver'] ?? [] From 1cc953a9af8b710b95e7be25775685ef5d13a17e Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 6 Oct 2022 10:02:26 +0200 Subject: [PATCH 212/321] PHPLIB-980: Make uri parameter for MongoDB\Client::__construct nullable (#986) --- docs/reference/method/MongoDBClient__construct.txt | 2 +- src/Client.php | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/reference/method/MongoDBClient__construct.txt b/docs/reference/method/MongoDBClient__construct.txt index 0b89b6906..07694c91e 100644 --- a/docs/reference/method/MongoDBClient__construct.txt +++ b/docs/reference/method/MongoDBClient__construct.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function __construct($uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = []) + function __construct(?string $uri = null, array $uriOptions = [], array $driverOptions = []) This constructor has the following parameters: diff --git a/src/Client.php b/src/Client.php index 0fd339081..bb12c3776 100644 --- a/src/Client.php +++ b/src/Client.php @@ -44,6 +44,8 @@ class Client { + public const DEFAULT_URI = 'mongodb://127.0.0.1/'; + /** @var array */ private static $defaultTypeMap = [ 'array' => BSONArray::class, @@ -91,14 +93,14 @@ class Client * @see https://mongodb.com/docs/manual/reference/connection-string/ * @see https://php.net/manual/en/mongodb-driver-manager.construct.php * @see https://php.net/manual/en/mongodb.persistence.php#mongodb.persistence.typemaps - * @param string $uri MongoDB connection string - * @param array $uriOptions Additional connection string options - * @param array $driverOptions Driver-specific options + * @param string|null $uri MongoDB connection string. If none is provided, this defaults to self::DEFAULT_URI. + * @param array $uriOptions Additional connection string options + * @param array $driverOptions Driver-specific options * @throws InvalidArgumentException for parameter/option parsing errors * @throws DriverInvalidArgumentException for parameter/option parsing errors in the driver * @throws DriverRuntimeException for other driver errors (e.g. connection errors) */ - public function __construct(string $uri = 'mongodb://127.0.0.1/', array $uriOptions = [], array $driverOptions = []) + public function __construct(?string $uri = null, array $uriOptions = [], array $driverOptions = []) { $driverOptions += ['typeMap' => self::$defaultTypeMap]; @@ -116,7 +118,7 @@ public function __construct(string $uri = 'mongodb://127.0.0.1/', array $uriOpti $driverOptions['driver'] = $this->mergeDriverInfo($driverOptions['driver'] ?? []); - $this->uri = $uri; + $this->uri = $uri ?? self::DEFAULT_URI; $this->typeMap = $driverOptions['typeMap']; unset($driverOptions['typeMap']); From c6974720b9107a444ba0b191565826f2e24c9139 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 6 Oct 2022 13:43:59 +0200 Subject: [PATCH 213/321] PHPLIB-950: Run legacy CSFLE tests on serverless (#988) * Download mongocryptd and crypt_shared for serverless tests * Export FLE secrets to enable testing * Run KMS servers when testing against serverless * PHPLIB-950: Run legacy CSFLE tests on serverless This syncs legacy CSFLE tests with mongodb/specifications@59a07b718253457d380f1e69cd51ad417f36e575 --- .evergreen/config.yml | 63 +++++++++++++++++++ .../ClientSideEncryptionSpecTest.php | 1 + .../tests/fle2-BypassQueryAnalysis.json | 3 +- .../tests/fle2-Compact.json | 3 +- .../tests/fle2-CreateCollection.json | 3 +- .../tests/fle2-DecryptExistingData.json | 3 +- .../tests/fle2-Delete.json | 3 +- ...EncryptedFields-vs-EncryptedFieldsMap.json | 3 +- .../fle2-EncryptedFields-vs-jsonSchema.json | 3 +- .../fle2-EncryptedFieldsMap-defaults.json | 3 +- .../tests/fle2-FindOneAndUpdate.json | 3 +- .../tests/fle2-InsertFind-Indexed.json | 3 +- .../tests/fle2-InsertFind-Unindexed.json | 3 +- .../tests/fle2-MissingKey.json | 3 +- .../tests/fle2-NoEncryption.json | 3 +- .../tests/fle2-Update.json | 3 +- ...e2-validatorAndPartialFieldExpression.json | 3 +- 17 files changed, 94 insertions(+), 15 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 999328f88..9d831b017 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -212,6 +212,55 @@ functions: - command: expansions.update params: file: src/serverless-expansion.yml + - command: shell.exec + params: + shell: "bash" + script: | + ${PREPARE_SHELL} + + if [ -z "${SERVERLESS_MONGODB_VERSION}" ]; then + echo "expected SERVERLESS_MONGODB_VERSION to be set" + exit 1 + fi + + # Download the enterprise server download for current platform to $MONGODB_BINARIES. + # This is required for tests that need mongocryptd. + # $MONGODB_BINARIES is added to the $PATH in fetch-source. + ${PYTHON3_BINARY} $DRIVERS_TOOLS/.evergreen/mongodl.py \ + --component archive \ + --version ${SERVERLESS_MONGODB_VERSION} \ + --edition enterprise \ + --out $MONGODB_BINARIES \ + --strip-path-components 2 + + # Download the crypt_shared dynamic library for the current platform. + ${PYTHON3_BINARY} $DRIVERS_TOOLS/.evergreen/mongodl.py \ + --component crypt_shared \ + --version ${SERVERLESS_MONGODB_VERSION} \ + --edition enterprise \ + --out . \ + --only "**/mongo_crypt_v1.*" \ + --strip-path-components 1 + + # Find the crypt_shared library file in the current directory and set the CRYPT_SHARED_LIB_PATH to + # the path of that file. Only look for .so, .dll, or .dylib files to prevent matching any other + # downloaded files. + CRYPT_SHARED_LIB_PATH="$(find $(pwd) -maxdepth 1 -type f \ + -name 'mongo_crypt_v1.so' -o \ + -name 'mongo_crypt_v1.dll' -o \ + -name 'mongo_crypt_v1.dylib')" + + # If we're on Windows, convert the "cygdrive" path to Windows-style paths. + if [ "Windows_NT" = "$OS" ]; then + CRYPT_SHARED_LIB_PATH=$(cygpath -m $CRYPT_SHARED_LIB_PATH) + fi + + echo "CRYPT_SHARED_LIB_PATH: $CRYPT_SHARED_LIB_PATH" >> crypt-expansion.yml + + # Load the expansion file to make an evergreen variable with the current unique version + - command: expansions.update + params: + file: crypt-expansion.yml "delete serverless instance": - command: shell.exec @@ -277,6 +326,19 @@ functions: working_dir: "src" script: | ${PREPARE_SHELL} + export AWS_ACCESS_KEY_ID="${client_side_encryption_aws_access_key_id}" + export AWS_SECRET_ACCESS_KEY="${client_side_encryption_aws_secret_access_key}" + export AZURE_TENANT_ID="${client_side_encryption_azure_tenant_id}" + export AZURE_CLIENT_ID="${client_side_encryption_azure_client_id}" + export AZURE_CLIENT_SECRET="${client_side_encryption_azure_client_secret}" + export GCP_EMAIL="${client_side_encryption_gcp_email}" + export GCP_PRIVATE_KEY="${client_side_encryption_gcp_privatekey}" + export KMIP_ENDPOINT="${client_side_encryption_kmip_endpoint}" + export KMS_ENDPOINT_EXPIRED="${client_side_encryption_kms_endpoint_expired}" + export KMS_ENDPOINT_WRONG_HOST="${client_side_encryption_kms_endpoint_wrong_host}" + export KMS_ENDPOINT_REQUIRE_CLIENT_CERT="${client_side_encryption_kms_endpoint_require_client_cert}" + export KMS_TLS_CA_FILE="${client_side_encryption_kms_tls_ca_file}" + export KMS_TLS_CERTIFICATE_KEY_FILE="${client_side_encryption_kms_tls_certificate_key_file}" export MONGODB_IS_SERVERLESS=on export MONGODB_USERNAME=${SERVERLESS_ATLAS_USER} export MONGODB_PASSWORD=${SERVERLESS_ATLAS_PASSWORD} @@ -505,6 +567,7 @@ tasks: tags: ["serverless"] commands: - func: "create serverless instance" + - func: "start kms servers" - func: "run serverless tests" - name: "test-loadBalanced" diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 7fff25e6d..cba0323f1 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -55,6 +55,7 @@ * * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption * @group csfle + * @group serverless */ class ClientSideEncryptionSpecTest extends FunctionalTestCase { diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json b/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json index 629faf189..b8d06e8bc 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json b/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json index 46da99cbf..6ca0f9ba0 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json index 6836f40e0..9f8db41f8 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json b/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json index c6d0bca0d..e622d3334 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json index 0e3e06396..868712774 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json index ea3eb4850..911b42863 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json index 1d3227ee7..f4386483d 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json index 030952e05..60820aae9 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json index b31438876..de1b5c5aa 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json index 81a549590..84b69d7de 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json index c1bdc9076..9b3143852 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json b/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json index 2db1cd770..4210da09e 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json b/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json index e9dd586c2..9d255bd49 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json index 87830af32..090f44f9a 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json index fab36f75a..e70ca7c72 100644 --- a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json +++ b/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json @@ -4,7 +4,8 @@ "minServerVersion": "6.0.0", "topology": [ "replicaset", - "sharded" + "sharded", + "load-balanced" ] } ], From ecdacff94528eb4bd27c5a053b34bbb2d457eb40 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 7 Oct 2022 08:37:26 +0200 Subject: [PATCH 214/321] PHPLIB-601: Document upcoming typing changes (#985) * Fix wrong information about group helper in upgrade guide * Rename upgrade guide to "Legacy Driver Upgrade Guide" * PHPLIB-601: Document upcoming typing changes * Update method signatures in documentation * Rename upgrade file to account for new version number * Document method signature changes by class * Fix wrong method signature in docs * Fix syntax and update wording --- UPGRADE-1.15.md | 66 +++++++++++++++++++ .../method/MongoDBClient-dropDatabase.txt | 2 +- .../method/MongoDBClient-selectCollection.txt | 2 +- .../method/MongoDBClient-selectDatabase.txt | 2 +- docs/reference/method/MongoDBClient__get.txt | 2 +- .../method/MongoDBCollection-distinct.txt | 2 +- .../method/MongoDBCollection__construct.txt | 2 +- ...oDBGridFSBucket-downloadToStreamByName.txt | 2 +- ...BGridFSBucket-openDownloadStreamByName.txt | 2 +- .../MongoDBGridFSBucket-openUploadStream.txt | 2 +- .../method/MongoDBGridFSBucket-rename.txt | 2 +- .../MongoDBGridFSBucket-uploadFromStream.txt | 2 +- .../method/MongoDBGridFSBucket__construct.txt | 2 +- docs/upgrade.txt | 8 +-- 14 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 UPGRADE-1.15.md diff --git a/UPGRADE-1.15.md b/UPGRADE-1.15.md new file mode 100644 index 000000000..d836ce3f1 --- /dev/null +++ b/UPGRADE-1.15.md @@ -0,0 +1,66 @@ +# UPGRADE FROM 1.x to 1.15 + +## Method signature changes + +### Parameter types + +Starting with 1.15, methods now declare types for their arguments. This will not +cause BC breaks unless you've passed a type that was incompatible with the type +previously documented in the PHPDoc comment. A list of changes can be found at +the bottom of this document. + +### Return types + +Return types will be added in version 2.0. These types are documented in a +PHPDoc comment and will eventually become a declared return type. You can +prepare for this change (which will trigger a BC break in any class you may +extend) by adding the correct return type to your class at this time. + +## Internal classes + +Internal classes (i.e. annotated with `@internal`) will become final where +possible in a future release. At the same time, we will add return types to +these internal classes. Note that internal classes are not covered by our +backward compatibility promise, and you should not instantiate such classes +directly. + +## Method signature changes by class + +### MongoDB\Client + +| 1.13 | 1.15 | +|-----------------------------------------------------------------------------------------------:|:--------------------------------------------------------------------------------------| +| `__construct($uri = 'mongodb://127.0.0.1', array $uriOptions = [], array $driverOptions = [])` | `__construct(?string $uri = null, array $uriOptions = [], array $driverOptions = [])` | +| `__get($databaseName)` | `__get(string $databaseName)` | +| `dropDatabase($databaseName, array $options = [])` | `dropDatabase(string $databaseName, array $options = [])` | +| `selectCollection($databaseName, $collectionName, array $options = [])` | `selectCollection(string $databaseName, string $collectionName, array $options = [])` | +| `selectDatabase($databaseName, array $options = [])` | `selectDatabase(string $databaseName, array $options = [])` | + +### MongoDB\Database + +| 1.13 | 1.15 | +|-----------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------| +| `__construct(MongoDB\Driver\Manager $manager, $databaseName, array $options = [])` | `__construct(MongoDB\Driver\Manager $manager, string $databaseName, array $options = [])` | +| `__get($collectionName)` | `__get(string $collectionName)` | +| `createCollection($collectionName, array $options = [])` | `createCollection(string $collectionName, array $options = [])` | +| `dropCollection($collectionName, array $options = [])` | `dropCollection(string $collectionName, array $options = [])` | +| `modifyCollection($collectionName, array $collectionOptions, array $options = [])` | `modifyCollection(string $collectionName, array $collectionOptions, array $options = [])` | +| `selectCollection($collectionName, array $options = [])` | `selectCollection(string $collectionName, array $options = [])` | + +### MongoDB\Collection + +| 1.13 | 1.15 | +|----------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------------------------| +| `__construct(MongoDB\Driver\Manager $manager, $databaseName, $collectionName, array $options = [])` | `__construct(MongoDB\Driver\Manager $manager, string $databaseName, string $collectionName, array $options = [])` | +| `distinct($fieldName, $filter = [], array $options = [])` | `distinct(string $fieldName, $filter = [], array $options = [])` | + +### MongoDB\GridFS\Bucket + +| 1.13 | 1.15 | +|-----------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------| +| `__construct(MongoDB\Driver\Manager $manager, $databaseName, array $options = [])` | `__construct(MongoDB\Driver\Manager $manager, string $databaseName, array $options = [])` | +| `downloadToStreamByName($filename, $destination, array $options = [])` | `downloadToStreamByName(string $filename, $destination, array $options = [])` | +| `openDownloadStreamByName($filename, array $options = [])` | `openDownloadStreamByName(string $filename, array $options = [])` | +| `openUploadStream($filename, array $options = [])` | `openUploadStream(string $filename, array $options = [])` | +| `uploadFromStream($filename, $source, array $options = [])` | `uploadFromStream(string $filename, $source, array $options = [])` | +| `rename($id, $newFilename)` | `rename($id, string $newFilename)` | diff --git a/docs/reference/method/MongoDBClient-dropDatabase.txt b/docs/reference/method/MongoDBClient-dropDatabase.txt index ccb303ffb..4369d07f2 100644 --- a/docs/reference/method/MongoDBClient-dropDatabase.txt +++ b/docs/reference/method/MongoDBClient-dropDatabase.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function dropDatabase($databaseName, array $options []): array|object + function dropDatabase(string $databaseName, array $options = []): array|object This method has the following parameters: diff --git a/docs/reference/method/MongoDBClient-selectCollection.txt b/docs/reference/method/MongoDBClient-selectCollection.txt index 6ce12df7b..34a251988 100644 --- a/docs/reference/method/MongoDBClient-selectCollection.txt +++ b/docs/reference/method/MongoDBClient-selectCollection.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function selectCollection($databaseName, $collectionName, array $options = []): MongoDB\Collection + function selectCollection(string $databaseName, string $collectionName, array $options = []): MongoDB\Collection This method has the following parameters: diff --git a/docs/reference/method/MongoDBClient-selectDatabase.txt b/docs/reference/method/MongoDBClient-selectDatabase.txt index 10dc4d8ad..73ecc2b95 100644 --- a/docs/reference/method/MongoDBClient-selectDatabase.txt +++ b/docs/reference/method/MongoDBClient-selectDatabase.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function selectDatabase($databaseName, array $options = []): MongoDB\Database + function selectDatabase(string $databaseName, array $options = []): MongoDB\Database This method has the following parameters: diff --git a/docs/reference/method/MongoDBClient__get.txt b/docs/reference/method/MongoDBClient__get.txt index c08245782..c0af748c3 100644 --- a/docs/reference/method/MongoDBClient__get.txt +++ b/docs/reference/method/MongoDBClient__get.txt @@ -21,7 +21,7 @@ Definition .. code-block:: php - function __get($databaseName): MongoDB\Database + function __get(string $databaseName): MongoDB\Database This method has the following parameters: diff --git a/docs/reference/method/MongoDBCollection-distinct.txt b/docs/reference/method/MongoDBCollection-distinct.txt index bf7ffb4c0..bb0c94ca5 100644 --- a/docs/reference/method/MongoDBCollection-distinct.txt +++ b/docs/reference/method/MongoDBCollection-distinct.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function distinct($fieldName, $filter = [], array $options = []): mixed[] + function distinct(string $fieldName, $filter = [], array $options = []): mixed[] This method has the following parameters: diff --git a/docs/reference/method/MongoDBCollection__construct.txt b/docs/reference/method/MongoDBCollection__construct.txt index c3ef0c6bf..e8077c73f 100644 --- a/docs/reference/method/MongoDBCollection__construct.txt +++ b/docs/reference/method/MongoDBCollection__construct.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function __construct(MongoDB\Driver\Manager $manager, $databaseName, $collectionName, array $options = []) + function __construct(MongoDB\Driver\Manager $manager, string $databaseName, string $collectionName, array $options = []) This constructor has the following parameters: diff --git a/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt b/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt index 002bdc654..a505e115c 100644 --- a/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt +++ b/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt @@ -20,7 +20,7 @@ Definition .. code-block:: php - function downloadToStreamByName($filename, $destination, array $options = []): void + function downloadToStreamByName(string $filename, $destination, array $options = []): void This method has the following parameters: diff --git a/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt b/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt index d9f7b5b44..f796fee03 100644 --- a/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt +++ b/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function openDownloadStreamByName($filename, array $options = []): resource + function openDownloadStreamByName(string $filename, array $options = []): resource This method has the following parameters: diff --git a/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt b/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt index 806ad6b8b..b27420f20 100644 --- a/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function openUploadStream($filename, array $options = []): resource + function openUploadStream(string $filename, array $options = []): resource This method has the following parameters: diff --git a/docs/reference/method/MongoDBGridFSBucket-rename.txt b/docs/reference/method/MongoDBGridFSBucket-rename.txt index 346ffd81f..a2fbfe32d 100644 --- a/docs/reference/method/MongoDBGridFSBucket-rename.txt +++ b/docs/reference/method/MongoDBGridFSBucket-rename.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function rename($id, $newFilename): void + function rename($id, string $newFilename): void This method has the following parameters: diff --git a/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt b/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt index b5d5abefc..fd2eceee7 100644 --- a/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function uploadFromStream($filename, $source, array $options = []): mixed + function uploadFromStream(string $filename, $source, array $options = []): mixed This method has the following parameters: diff --git a/docs/reference/method/MongoDBGridFSBucket__construct.txt b/docs/reference/method/MongoDBGridFSBucket__construct.txt index 49211fba7..5eeee5fc7 100644 --- a/docs/reference/method/MongoDBGridFSBucket__construct.txt +++ b/docs/reference/method/MongoDBGridFSBucket__construct.txt @@ -19,7 +19,7 @@ Definition .. code-block:: php - function __construct(MongoDB\Driver\Manager $manager, $databaseName, array $options = []) + function __construct(MongoDB\Driver\Manager $manager, string $databaseName, array $options = []) This constructor has the following parameters: diff --git a/docs/upgrade.txt b/docs/upgrade.txt index b3d9ab38d..200e49c99 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -1,6 +1,6 @@ -============= -Upgrade Guide -============= +=========================== +Legacy Driver Upgrade Guide +=========================== .. default-domain:: mongodb @@ -281,7 +281,7 @@ inadvertent and potentially dangerous :manual:`full-document replacements Group Command Helper ~~~~~~~~~~~~~~~~~~~~ -:phpclass:`MongoDB\\Collection` does have a helper method for the +:phpclass:`MongoDB\\Collection` does not have a helper method for the :manual:`group ` command. The following example demonstrates how to execute a group command using the :phpmethod:`MongoDB\\Database::command()` method: From c2f187365e36b6191e297dcc36f256362ff957aa Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 11 Oct 2022 08:20:03 +0200 Subject: [PATCH 215/321] Bump psalm requirement to 4.28 (#992) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f51b0b192..be1348928 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,7 @@ "squizlabs/php_codesniffer": "^3.6", "doctrine/coding-standard": "^9.0", "symfony/phpunit-bridge": "^5.2", - "vimeo/psalm": "^4.x-dev" + "vimeo/psalm": "^4.28" }, "autoload": { "psr-4": { "MongoDB\\": "src/" }, From cb0f067d0f425625e759266e795418de3468067a Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 11 Oct 2022 21:37:28 +0800 Subject: [PATCH 216/321] PHPLIB-1001, PHPLIB-1010, PHPLIB-1011: Improvements to $$type operator (#991) * PHPLIB-1001: Support "number" alias in IsBsonType constraint Also revises instantiation of deprecated BSON types and fixes an assertion message. * PHPLIB-1010: Relax acceptance of Int64 for $$type operators * PHPLIB-1011: Support asserting multiple types in legacy $$type operator This refactors DocumentsMatchConstraint to use the IsBsonType constraint from the unified test runner. --- tests/SpecTests/DocumentsMatchConstraint.php | 169 ++---------------- .../DocumentsMatchConstraintTest.php | 40 ++++- .../Constraint/IsBsonType.php | 12 +- .../Constraint/IsBsonTypeTest.php | 34 +++- 4 files changed, 79 insertions(+), 176 deletions(-) diff --git a/tests/SpecTests/DocumentsMatchConstraint.php b/tests/SpecTests/DocumentsMatchConstraint.php index 9940586c4..3dde8e705 100644 --- a/tests/SpecTests/DocumentsMatchConstraint.php +++ b/tests/SpecTests/DocumentsMatchConstraint.php @@ -4,28 +4,11 @@ use ArrayObject; use InvalidArgumentException; -use MongoDB\BSON\BinaryInterface; -use MongoDB\BSON\DBPointer; -use MongoDB\BSON\Decimal128; use MongoDB\BSON\Int64; -use MongoDB\BSON\Javascript; -use MongoDB\BSON\MaxKey; -use MongoDB\BSON\MinKey; -use MongoDB\BSON\ObjectId; -use MongoDB\BSON\Regex; -use MongoDB\BSON\Symbol; -use MongoDB\BSON\Timestamp; -use MongoDB\BSON\Undefined; -use MongoDB\BSON\UTCDateTime; use MongoDB\Model\BSONArray; use MongoDB\Model\BSONDocument; +use MongoDB\Tests\UnifiedSpecTests\Constraint\IsBsonType; use PHPUnit\Framework\Constraint\Constraint; -use PHPUnit\Framework\Constraint\IsInstanceOf; -use PHPUnit\Framework\Constraint\IsNull; -use PHPUnit\Framework\Constraint\IsType; -use PHPUnit\Framework\Constraint\LogicalAnd; -use PHPUnit\Framework\Constraint\LogicalNot; -use PHPUnit\Framework\Constraint\LogicalOr; use RuntimeException; use SebastianBergmann\Comparator\ComparisonFailure; use SebastianBergmann\Comparator\Factory; @@ -39,7 +22,12 @@ use function is_float; use function is_int; use function is_object; -use function method_exists; +use function PHPUnit\Framework\assertThat; +use function PHPUnit\Framework\containsOnly; +use function PHPUnit\Framework\isInstanceOf; +use function PHPUnit\Framework\isType; +use function PHPUnit\Framework\logicalAnd; +use function PHPUnit\Framework\logicalOr; use function sprintf; use const PHP_INT_SIZE; @@ -132,143 +120,18 @@ private function doEvaluate($other, $description = '', $returnResult = false) } /** - * @param mixed $actualValue + * @param string|string[] $expectedType + * @param mixed $actualValue */ - private function assertBSONType(string $expectedType, $actualValue): void + private function assertBSONType($expectedType, $actualValue): void { - switch ($expectedType) { - case 'double': - (new IsType('float'))->evaluate($actualValue); + assertThat( + $expectedType, + logicalOr(isType('string'), logicalAnd(isInstanceOf(BSONArray::class), containsOnly('string'))), + '$$type requires string or string[]' + ); - return; - - case 'string': - (new IsType('string'))->evaluate($actualValue); - - return; - - case 'object': - $constraints = [ - new IsType('object'), - new LogicalNot(new IsInstanceOf(BSONArray::class)), - ]; - - // LogicalAnd::fromConstraints was introduced in PHPUnit 6.5.0. - // This check can be removed when the PHPUnit dependency is bumped to that version - if (method_exists(LogicalAnd::class, 'fromConstraints')) { - $constraint = LogicalAnd::fromConstraints(...$constraints); - } else { - $constraint = new LogicalAnd(); - $constraint->setConstraints($constraints); - } - - $constraint->evaluate($actualValue); - - return; - - case 'array': - $constraints = [ - new IsType('array'), - new IsInstanceOf(BSONArray::class), - ]; - - // LogicalOr::fromConstraints was introduced in PHPUnit 6.5.0. - // This check can be removed when the PHPUnit dependency is bumped to that version - if (method_exists(LogicalOr::class, 'fromConstraints')) { - $constraint = LogicalOr::fromConstraints(...$constraints); - } else { - $constraint = new LogicalOr(); - $constraint->setConstraints($constraints); - } - - $constraint->evaluate($actualValue); - - return; - - case 'binData': - (new IsInstanceOf(BinaryInterface::class))->evaluate($actualValue); - - return; - - case 'undefined': - (new IsInstanceOf(Undefined::class))->evaluate($actualValue); - - return; - - case 'objectId': - (new IsInstanceOf(ObjectId::class))->evaluate($actualValue); - - return; - - case 'boolean': - (new IsType('bool'))->evaluate($actualValue); - - return; - - case 'date': - (new IsInstanceOf(UTCDateTime::class))->evaluate($actualValue); - - return; - - case 'null': - (new IsNull())->evaluate($actualValue); - - return; - - case 'regex': - (new IsInstanceOf(Regex::class))->evaluate($actualValue); - - return; - - case 'dbPointer': - (new IsInstanceOf(DBPointer::class))->evaluate($actualValue); - - return; - - case 'javascript': - (new IsInstanceOf(Javascript::class))->evaluate($actualValue); - - return; - - case 'symbol': - (new IsInstanceOf(Symbol::class))->evaluate($actualValue); - - return; - - case 'int': - (new IsType('int'))->evaluate($actualValue); - - return; - - case 'timestamp': - (new IsInstanceOf(Timestamp::class))->evaluate($actualValue); - - return; - - case 'long': - if (PHP_INT_SIZE == 4) { - (new IsInstanceOf(Int64::class))->evaluate($actualValue); - } else { - (new IsType('int'))->evaluate($actualValue); - } - - return; - - case 'decimal': - (new IsInstanceOf(Decimal128::class))->evaluate($actualValue); - - return; - - case 'minKey': - (new IsInstanceOf(MinKey::class))->evaluate($actualValue); - - return; - - case 'maxKey': - (new IsInstanceOf(MaxKey::class))->evaluate($actualValue); - - return; - } + IsBsonType::anyOf(...(array) $expectedType)->evaluate($actualValue); } /** diff --git a/tests/SpecTests/DocumentsMatchConstraintTest.php b/tests/SpecTests/DocumentsMatchConstraintTest.php index 1917d4c69..4e7e3203a 100644 --- a/tests/SpecTests/DocumentsMatchConstraintTest.php +++ b/tests/SpecTests/DocumentsMatchConstraintTest.php @@ -84,9 +84,11 @@ public function testBSONTypeAssertions($type, $value): void public function provideBSONTypes() { - $undefined = toPHP(fromJSON('{ "undefined": {"$undefined": true} }')); - $symbol = toPHP(fromJSON('{ "symbol": {"$symbol": "test"} }')); - $dbPointer = toPHP(fromJSON('{ "dbPointer": {"$dbPointer": {"$ref": "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } }} }')); + $undefined = toPHP(fromJSON('{ "x": {"$undefined": true} }'))->x; + $symbol = toPHP(fromJSON('{ "x": {"$symbol": "test"} }'))->x; + $dbPointer = toPHP(fromJSON('{ "x": {"$dbPointer": {"$ref": "db.coll", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } }} }'))->x; + $int64 = unserialize('C:18:"MongoDB\BSON\Int64":28:{a:1:{s:7:"integer";s:1:"1";}}'); + $long = PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296; return [ 'double' => ['double', 1.4], @@ -94,24 +96,46 @@ public function provideBSONTypes() 'object' => ['object', new BSONDocument()], 'array' => ['array', ['foo']], 'binData' => ['binData', new Binary('', 0)], - 'undefined' => ['undefined', $undefined->undefined], + 'undefined' => ['undefined', $undefined], 'objectId' => ['objectId', new ObjectId()], - 'boolean' => ['boolean', true], + 'bool' => ['bool', true], 'date' => ['date', new UTCDateTime()], 'null' => ['null', null], 'regex' => ['regex', new Regex('.*')], - 'dbPointer' => ['dbPointer', $dbPointer->dbPointer], + 'dbPointer' => ['dbPointer', $dbPointer], 'javascript' => ['javascript', new Javascript('foo = 1;')], - 'symbol' => ['symbol', $symbol->symbol], + 'symbol' => ['symbol', $symbol], 'int' => ['int', 1], 'timestamp' => ['timestamp', new Timestamp(0, 0)], - 'long' => ['long', PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296], + 'long(int64)' => ['long', $int64], + 'long(long)' => ['long', $long], 'decimal' => ['decimal', new Decimal128('18446744073709551616')], 'minKey' => ['minKey', new MinKey()], 'maxKey' => ['maxKey', new MaxKey()], + 'number(double)' => ['number', 1.4], + 'number(decimal)' => ['number', new Decimal128('18446744073709551616')], + 'number(int)' => ['number', 1], + 'number(int64)' => ['number', $int64], + 'number(long)' => ['number', $long], ]; } + public function testBSONTypeAssertionsWithMultipleTypes(): void + { + $c1 = new DocumentsMatchConstraint(['x' => ['$$type' => ['double', 'int']]]); + + $this->assertResult(true, $c1, ['x' => 1], 'int is double or int'); + $this->assertResult(true, $c1, ['x' => 1.4], 'double is double or int'); + $this->assertResult(false, $c1, ['x' => 'foo'], 'string is not double or int'); + + $c2 = new DocumentsMatchConstraint(['x' => ['$$type' => ['number', 'string']]]); + + $this->assertResult(true, $c2, ['x' => 1], 'int is number or string'); + $this->assertResult(true, $c2, ['x' => 1.4], 'double is number or string'); + $this->assertResult(true, $c2, ['x' => 'foo'], 'string is number or string'); + $this->assertResult(false, $c2, ['x' => true], 'bool is not number or string'); + } + /** * @dataProvider errorMessageProvider */ diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonType.php b/tests/UnifiedSpecTests/Constraint/IsBsonType.php index 8d07a250f..16cbdb5bc 100644 --- a/tests/UnifiedSpecTests/Constraint/IsBsonType.php +++ b/tests/UnifiedSpecTests/Constraint/IsBsonType.php @@ -38,8 +38,6 @@ use function range; use function sprintf; -use const PHP_INT_SIZE; - final class IsBsonType extends Constraint { use ConstraintTrait; @@ -67,6 +65,7 @@ final class IsBsonType extends Constraint 'decimal', 'minKey', 'maxKey', + 'number', ]; /** @var string */ @@ -152,11 +151,7 @@ private function doMatches($other): bool return $other instanceof TimestampInterface; case 'long': - if (PHP_INT_SIZE == 4) { - return $other instanceof Int64; - } - - return is_int($other); + return is_int($other) || $other instanceof Int64; case 'decimal': return $other instanceof Decimal128Interface; @@ -167,6 +162,9 @@ private function doMatches($other): bool case 'maxKey': return $other instanceof MaxKeyInterface; + case 'number': + return is_int($other) || $other instanceof Int64 || is_float($other) || $other instanceof Decimal128Interface; + default: // This should already have been caught in the constructor throw new LogicException('Unsupported type: ' . $this->type); diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php index 730dc7935..ae0f88c2e 100644 --- a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php +++ b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php @@ -38,9 +38,11 @@ public function testConstraint($type, $value): void public function provideTypes() { - $undefined = toPHP(fromJSON('{ "undefined": {"$undefined": true} }')); - $symbol = toPHP(fromJSON('{ "symbol": {"$symbol": "test"} }')); - $dbPointer = toPHP(fromJSON('{ "dbPointer": {"$dbPointer": {"$ref": "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } }} }')); + $undefined = toPHP(fromJSON('{ "x": {"$undefined": true} }'))->x; + $symbol = toPHP(fromJSON('{ "x": {"$symbol": "test"} }'))->x; + $dbPointer = toPHP(fromJSON('{ "x": {"$dbPointer": {"$ref": "db.coll", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } }} }'))->x; + $int64 = unserialize('C:18:"MongoDB\BSON\Int64":28:{a:1:{s:7:"integer";s:1:"1";}}'); + $long = PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296; return [ 'double' => ['double', 1.4], @@ -52,22 +54,28 @@ public function provideTypes() 'array(indexed array)' => ['array', ['foo']], 'array(BSONArray)' => ['array', new BSONArray()], 'binData' => ['binData', new Binary('', 0)], - 'undefined' => ['undefined', $undefined->undefined], + 'undefined' => ['undefined', $undefined], 'objectId' => ['objectId', new ObjectId()], 'bool' => ['bool', true], 'date' => ['date', new UTCDateTime()], 'null' => ['null', null], 'regex' => ['regex', new Regex('.*')], - 'dbPointer' => ['dbPointer', $dbPointer->dbPointer], + 'dbPointer' => ['dbPointer', $dbPointer], 'javascript' => ['javascript', new Javascript('foo = 1;')], - 'symbol' => ['symbol', $symbol->symbol], + 'symbol' => ['symbol', $symbol], 'javascriptWithScope' => ['javascriptWithScope', new Javascript('foo = 1;', ['x' => 1])], 'int' => ['int', 1], 'timestamp' => ['timestamp', new Timestamp(0, 0)], - 'long' => ['long', PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296], + 'long(int64)' => ['long', $int64], + 'long(long)' => ['long', $long], 'decimal' => ['decimal', new Decimal128('18446744073709551616')], 'minKey' => ['minKey', new MinKey()], 'maxKey' => ['maxKey', new MaxKey()], + 'number(double)' => ['number', 1.4], + 'number(decimal)' => ['number', new Decimal128('18446744073709551616')], + 'number(int)' => ['number', 1], + 'number(int64)' => ['number', $int64], + 'number(long)' => ['number', $long], ]; } @@ -89,10 +97,20 @@ public function testAnyOf(): void $c = IsBsonType::anyOf('double', 'int'); $this->assertResult(true, $c, 1, 'int is double or int'); - $this->assertResult(true, $c, 1.4, 'int is double or int'); + $this->assertResult(true, $c, 1.4, 'double is double or int'); $this->assertResult(false, $c, 'foo', 'string is not double or int'); } + public function testAnyOfWithNumberAlias(): void + { + $c = IsBsonType::anyOf('number', 'string'); + + $this->assertResult(true, $c, 1, 'int is number or string'); + $this->assertResult(true, $c, 1.4, 'double is number or string'); + $this->assertResult(true, $c, 'foo', 'string is number or string'); + $this->assertResult(false, $c, true, 'bool is not number or string'); + } + public function testErrorMessage(): void { $c = new IsBsonType('string'); From f7ba251fb2885402aeb7e1c2860dfb69008e4f65 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 12 Oct 2022 09:43:11 +0200 Subject: [PATCH 217/321] Add Github Actions workflow to build documentation (#993) * Add workflow to build and check docs * Fix docs build warnings --- .github/workflows/docs.yml | 56 +++++++++++++++++++ docs/reference/bson.txt | 8 +-- .../method/MongoDBChangeStream-current.txt | 2 +- .../method/MongoDBChangeStream-key.txt | 2 +- 4 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..e8cd6ebc3 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,56 @@ +name: "Docs" + +on: + pull_request: + branches: + - "v*.*" + - "master" + - "feature/*" + push: + branches: + - "v*.*" + - "master" + - "feature/*" + +jobs: + giza: + name: "Build Docs" + runs-on: "ubuntu-20.04" + + steps: + - name: "Checkout library" + uses: "actions/checkout@v3" + with: + path: library + fetch-depth: 2 + + - name: "Checkout docs" + uses: "actions/checkout@v3" + with: + repository: mongodb/docs-php-library + path: docs + fetch-depth: 2 + + - name: "Setup python" + uses: actions/setup-python@v4 + with: + python-version: '2.7' + + # The requirements file installs urllib3 with an incompatible version; we replace it with one that works + - name: "Install giza" + run: | + pip install -r https://raw.githubusercontent.com/mongodb/docs-tools/master/giza/requirements.txt + pip install urllib3==1.25.2 + + - name: "Sync documentation" + run: "rsync -a library/docs/ docs/source/" + + - name: "Run Giza" + run: "giza make publish" + working-directory: docs + + - name: "Upload built documentation" + uses: actions/upload-artifact@v3 + with: + name: php-library-docs.tar.gz + path: docs/build/public/master/php-library.tar.gz diff --git a/docs/reference/bson.txt b/docs/reference/bson.txt index 2d4851a12..7ac5b6bc6 100644 --- a/docs/reference/bson.txt +++ b/docs/reference/bson.txt @@ -14,8 +14,8 @@ Overview -------- MongoDB stores data records as BSON documents. BSON is a binary representation -of :term:`JSON` documents, though it contains more data types than JSON. For the -BSON spec, see `bsonspec.org `_. +of JSON documents, though it contains more data types than JSON. For the BSON +spec, see `bsonspec.org `_. By default, the |php-library| returns BSON documents as :phpclass:`MongoDB\\Model\\BSONDocument` objects and BSON arrays as @@ -106,7 +106,7 @@ of the PHP class in a special property within the BSON document. When deserializing a PHP variable from BSON, the encoded class name of a :php:`Persistable ` object will override any class specified in the type map, but it will not override ``"array"`` and - ``"stdClass"`` or ``"object"``. This is discussed in the + ``"stdClass"`` or ``"object"``. This is discussed in the :php:`persistence specification ` but it bears repeating. @@ -121,7 +121,7 @@ Consider the following class definition: private $id; private $name; private $createdAt; - + public function __construct($name) { $this->id = new MongoDB\BSON\ObjectId; diff --git a/docs/reference/method/MongoDBChangeStream-current.txt b/docs/reference/method/MongoDBChangeStream-current.txt index 8057dbaa2..a85786073 100644 --- a/docs/reference/method/MongoDBChangeStream-current.txt +++ b/docs/reference/method/MongoDBChangeStream-current.txt @@ -103,4 +103,4 @@ See Also - :ref:`Tailable Cursor Iteration ` - :manual:`Change Streams ` documentation in the MongoDB manual - :manual:`Change Events ` documentation in the - MongoDB manual \ No newline at end of file + MongoDB manual diff --git a/docs/reference/method/MongoDBChangeStream-key.txt b/docs/reference/method/MongoDBChangeStream-key.txt index 6225c11f6..de4754b4f 100644 --- a/docs/reference/method/MongoDBChangeStream-key.txt +++ b/docs/reference/method/MongoDBChangeStream-key.txt @@ -73,4 +73,4 @@ See Also - :phpmethod:`MongoDB\\Database::watch()` - :php:`Iterator::key() ` - :ref:`Tailable Cursor Iteration ` -- :manual:`Change Streams ` documentation in the MongoDB manual \ No newline at end of file +- :manual:`Change Streams ` documentation in the MongoDB manual From 1043a3a5fb2e1e737c00eccd24a0d87c937ab0d2 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 12 Oct 2022 10:45:53 +0200 Subject: [PATCH 218/321] PHPLIB-989: Move persistable class documentation to tutorial (#987) * PHPLIB-989: Move persistable class documentation to tutorial * Move legacy driver section from BSON reference to upgrade guide * Move type map documentation to persistable classes tutorial * Rename persistence tutorial and move sections around --- docs/index.txt | 2 + docs/reference/bson.txt | 214 +-------------------------- docs/tutorial.txt | 1 + docs/tutorial/modeling-bson-data.txt | 158 ++++++++++++++++++++ docs/upgrade.txt | 71 ++++++++- 5 files changed, 232 insertions(+), 214 deletions(-) create mode 100644 docs/tutorial/modeling-bson-data.txt diff --git a/docs/index.txt b/docs/index.txt index 77890982c..5cbf328a4 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -35,6 +35,8 @@ following pages should help you get started: - :doc:`/tutorial/gridfs` +- :doc:`/tutorial/modeling-bson-data` + - :doc:`/reference/bson` Code examples can be found in the ``examples`` directory in the source code. diff --git a/docs/reference/bson.txt b/docs/reference/bson.txt index 7ac5b6bc6..b9fbbaa2c 100644 --- a/docs/reference/bson.txt +++ b/docs/reference/bson.txt @@ -21,8 +21,8 @@ By default, the |php-library| returns BSON documents as :phpclass:`MongoDB\\Model\\BSONDocument` objects and BSON arrays as :phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. -BSON Classes ------------- +Classes +------- .. phpclass:: MongoDB\\Model\\BSONArray @@ -49,213 +49,3 @@ BSON Classes class. During BSON and JSON serialization, instances of this class will serialize as a document type (:php:`object casting ` is used internally). - -.. _php-type-map: - -Type Maps ---------- - -Most methods that read data from MongoDB support a ``typeMap`` option, which -allows control over how BSON is converted to PHP. Additionally, -the :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and -:phpclass:`MongoDB\\Collection` classes accept a ``typeMap`` option, which can -be used to specify a default type map to apply to any supporting methods and -selected classes (e.g. :phpmethod:`MongoDB\\Client::selectDatabase()`). - -The :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and -:phpclass:`MongoDB\\Collection` classes use the following type map by -default: - -.. code-block:: php - - [ - 'array' => 'MongoDB\Model\BSONArray', - 'document' => 'MongoDB\Model\BSONDocument', - 'root' => 'MongoDB\Model\BSONDocument', - ] - -The type map above will convert BSON documents and arrays to -:phpclass:`MongoDB\\Model\\BSONDocument` and -:phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. The ``root`` and -``document`` keys are used to distinguish the top-level BSON document from -embedded documents, respectively. - -A type map may specify any class that implements -:php:`MongoDB\\BSON\\Unserializable ` as well as -``"array"``, ``"stdClass``", and ``"object"`` (``"stdClass``" and ``"object"`` -are aliases of one another). - -.. seealso:: :php:`Deserialization from BSON ` in the PHP manual - -``Persistable`` Classes ------------------------ - -The driver's :php:`persistence specification ` outlines how -classes implementing its :php:`MongoDB\\BSON\\Persistable -` interface are serialized to and deserialized from -BSON. The :php:`Persistable ` interface is analogous -to PHP's :php:`Serializable interface `. - -The driver automatically handles serialization and deserialization for classes -implementing the :php:`Persistable ` interface without -requiring the use of the ``typeMap`` option. This is done by encoding the name -of the PHP class in a special property within the BSON document. - -.. note:: - - When deserializing a PHP variable from BSON, the encoded class name of a - :php:`Persistable ` object will override any class - specified in the type map, but it will not override ``"array"`` and - ``"stdClass"`` or ``"object"``. This is discussed in the - :php:`persistence specification ` but it bears - repeating. - -Consider the following class definition: - -.. code-block:: php - - id = new MongoDB\BSON\ObjectId; - $this->name = (string) $name; - $this->createdAt = new MongoDB\BSON\UTCDateTime; - } - - function bsonSerialize() - { - return [ - '_id' => $this->id, - 'name' => $this->name, - 'createdAt' => $this->createdAt, - ]; - } - - function bsonUnserialize(array $data) - { - $this->id = $data['_id']; - $this->name = $data['name']; - $this->createdAt = $data['createdAt']; - } - } - -The following example constructs a ``Person`` object, inserts it into the -database, and reads it back as an object of the same type: - -.. code-block:: php - - test->persons; - - $result = $collection->insertOne(new Person('Bob')); - - $person = $collection->findOne(['_id' => $result->getInsertedId()]); - - var_dump($person); - -The output would then resemble: - -.. code-block:: none - - object(Person)#18 (3) { - ["id":"Person":private]=> - object(MongoDB\BSON\ObjectId)#15 (1) { - ["oid"]=> - string(24) "56fad2c36118fd2e9820cfc1" - } - ["name":"Person":private]=> - string(3) "Bob" - ["createdAt":"Person":private]=> - object(MongoDB\BSON\UTCDateTime)#17 (1) { - ["milliseconds"]=> - int(1459278531218) - } - } - -The same document in the MongoDB shell might display as: - -.. code-block:: js - - { - "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), - "__pclass" : BinData(128,"UGVyc29u"), - "name" : "Bob", - "createdAt" : ISODate("2016-03-29T19:08:51.218Z") - } - -.. note:: - - :php:`MongoDB\\BSON\\Persistable ` may only be used - for root and embedded BSON documents. It may not be used for BSON arrays. - -Emulating the Legacy Driver ---------------------------- - -The legacy ``mongo`` extension returned both BSON documents and arrays as PHP -arrays. While PHP arrays are convenient to work with, this behavior was -problematic: - -- Different BSON types could deserialize to the same PHP value (e.g. - ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the - original BSON type. - -- Numerically-indexed PHP arrays would be serialized as BSON documents if there - was a gap in their key sequence. Such gaps were easily caused by unsetting a - key to remove an element and forgetting to numerically reindex the array. - -The |php-library|'s :phpclass:`BSONDocument ` and -:phpclass:`BSONArray ` classes address these concerns -by preserving the BSON type information during serialization and -deserialization; however, some users may still prefer the legacy behavior. If -desired, you can use the ``typeMap`` option to have the library return -everything as a PHP array: - -.. code-block:: php - - [ - 'array' => 'array', - 'document' => 'array', - 'root' => 'array', - ], - ] - ); - - $document = $client->test->zips->findOne(['_id' => '94301']); - - var_dump($document); - -The above example would output something similar to: - -.. code-block:: php - - array(5) { - ["_id"]=> - string(5) "94301" - ["city"]=> - string(9) "PALO ALTO" - ["loc"]=> - array(2) { - [0]=> - float(-122.149685) - [1]=> - float(37.444324) - } - ["pop"]=> - int(15965) - ["state"]=> - string(2) "CA" - } diff --git a/docs/tutorial.txt b/docs/tutorial.txt index a749af2d1..91333fb45 100644 --- a/docs/tutorial.txt +++ b/docs/tutorial.txt @@ -17,4 +17,5 @@ Tutorials /tutorial/indexes /tutorial/tailable-cursor /tutorial/example-data + /tutorial/modeling-bson-data /tutorial/stable-api diff --git a/docs/tutorial/modeling-bson-data.txt b/docs/tutorial/modeling-bson-data.txt new file mode 100644 index 000000000..8d2e90064 --- /dev/null +++ b/docs/tutorial/modeling-bson-data.txt @@ -0,0 +1,158 @@ +================== +Modeling BSON Data +================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + + +Type Maps +--------- + +Most methods that read data from MongoDB support a ``typeMap`` option, which +allows control over how BSON is converted to PHP. Additionally, +the :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and +:phpclass:`MongoDB\\Collection` classes accept a ``typeMap`` option, which can +be used to specify a default type map to apply to any supporting methods and +selected classes (e.g. :phpmethod:`MongoDB\\Client::selectDatabase()`). + +The :phpclass:`MongoDB\\Client`, :phpclass:`MongoDB\\Database`, and +:phpclass:`MongoDB\\Collection` classes use the following type map by +default: + +.. code-block:: php + + [ + 'array' => 'MongoDB\Model\BSONArray', + 'document' => 'MongoDB\Model\BSONDocument', + 'root' => 'MongoDB\Model\BSONDocument', + ] + +The type map above will convert BSON documents and arrays to +:phpclass:`MongoDB\\Model\\BSONDocument` and +:phpclass:`MongoDB\\Model\\BSONArray` objects, respectively. The ``root`` and +``document`` keys are used to distinguish the top-level BSON document from +embedded documents, respectively. + +A type map may specify any class that implements +:php:`MongoDB\\BSON\\Unserializable ` as well as +``"array"``, ``"stdClass``", and ``"object"`` (``"stdClass``" and ``"object"`` +are aliases of one another). + +.. seealso:: :php:`Deserialization from BSON ` in the PHP manual + + +Persistable Classes +------------------- + +The driver's :php:`persistence specification ` outlines how +classes implementing its :php:`MongoDB\\BSON\\Persistable +` interface are serialized to and deserialized from +BSON. The :php:`Persistable ` interface is analogous +to PHP's :php:`Serializable interface `. + +The driver automatically handles serialization and deserialization for classes +implementing the :php:`Persistable ` interface without +requiring the use of the ``typeMap`` option. This is done by encoding the name +of the PHP class in a special property within the BSON document. + +.. note:: + + When deserializing a PHP variable from BSON, the encoded class name of a + :php:`Persistable ` object will override any class + specified in the type map, but it will not override ``"array"`` and + ``"stdClass"`` or ``"object"``. This is discussed in the + :php:`persistence specification ` but it bears + repeating. + +Consider the following class definition: + +.. code-block:: php + + id = new MongoDB\BSON\ObjectId; + $this->name = $name; + $this->createdAt = new MongoDB\BSON\UTCDateTime; + } + + function bsonSerialize() + { + return [ + '_id' => $this->id, + 'name' => $this->name, + 'createdAt' => $this->createdAt, + ]; + } + + function bsonUnserialize(array $data) + { + $this->id = $data['_id']; + $this->name = $data['name']; + $this->createdAt = $data['createdAt']; + } + } + +The following example constructs a ``Person`` object, inserts it into the +database, and reads it back as an object of the same type: + +.. code-block:: php + + test->persons; + + $result = $collection->insertOne(new Person('Bob')); + + $person = $collection->findOne(['_id' => $result->getInsertedId()]); + + var_dump($person); + +The output would then resemble: + +.. code-block:: none + + object(Person)#18 (3) { + ["id":"Person":private]=> + object(MongoDB\BSON\ObjectId)#15 (1) { + ["oid"]=> + string(24) "56fad2c36118fd2e9820cfc1" + } + ["name":"Person":private]=> + string(3) "Bob" + ["createdAt":"Person":private]=> + object(MongoDB\BSON\UTCDateTime)#17 (1) { + ["milliseconds"]=> + int(1459278531218) + } + } + +The same document in the MongoDB shell might display as: + +.. code-block:: js + + { + "_id" : ObjectId("56fad2c36118fd2e9820cfc1"), + "__pclass" : BinData(128,"UGVyc29u"), + "name" : "Bob", + "createdAt" : ISODate("2016-03-29T19:08:51.218Z") + } + +.. note:: + + :php:`MongoDB\\BSON\\Persistable ` may only be used + for root and embedded BSON documents. It may not be used for BSON arrays. +.. _php-type-map: diff --git a/docs/upgrade.txt b/docs/upgrade.txt index 200e49c99..4a67b7fbe 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -23,8 +23,11 @@ implements the ``mongo`` extension API using this library and the new driver. While this adapter library is not officially supported by MongoDB, it does bear mentioning. -BSON Type Classes ------------------ +BSON +---- + +Type Classes +~~~~~~~~~~~~ When upgrading from the legacy driver, type classes such as MongoId must be replaced with classes in the @@ -103,6 +106,70 @@ the new driver. driver also does not provide any helpers for working with DBRef objects, since their use is not encouraged. +Emulating the Legacy Driver +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The legacy ``mongo`` extension returned both BSON documents and arrays as PHP +arrays. While PHP arrays are convenient to work with, this behavior was +problematic: + +- Different BSON types could deserialize to the same PHP value (e.g. + ``{"0": "foo"}`` and ``["foo"]``), which made it impossible to infer the + original BSON type. + +- Numerically-indexed PHP arrays would be serialized as BSON documents if there + was a gap in their key sequence. Such gaps were easily caused by unsetting a + key to remove an element and forgetting to numerically reindex the array. + +The |php-library|'s :phpclass:`BSONDocument ` and +:phpclass:`BSONArray ` classes address these concerns +by preserving the BSON type information during serialization and +deserialization; however, some users may still prefer the legacy behavior. If +desired, you can use the ``typeMap`` option to have the library return +everything as a PHP array: + +.. code-block:: php + + [ + 'array' => 'array', + 'document' => 'array', + 'root' => 'array', + ], + ] + ); + + $document = $client->test->zips->findOne(['_id' => '94301']); + + var_dump($document); + +The above example would output something similar to: + +.. code-block:: php + + array(5) { + ["_id"]=> + string(5) "94301" + ["city"]=> + string(9) "PALO ALTO" + ["loc"]=> + array(2) { + [0]=> + float(-122.149685) + [1]=> + float(37.444324) + } + ["pop"]=> + int(15965) + ["state"]=> + string(2) "CA" + } + Collection API -------------- From 2e99cd83f551cd28d022c7e80dbd47ed4c558dcc Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 17 Oct 2022 11:58:55 +0800 Subject: [PATCH 219/321] PHPLIB-909: expectedError.errorResponse assertion (#989) Synced with mongodb/specifications@5f8d058e5ecbc24f98807713d88527f79581d2e9 --- tests/UnifiedSpecTests/ExpectedError.php | 16 +++ tests/UnifiedSpecTests/UnifiedSpecTest.php | 5 + tests/UnifiedSpecTests/UnifiedTestRunner.php | 4 +- tests/UnifiedSpecTests/Util.php | 4 +- .../modifyCollection-errorResponse.json | 118 ++++++++++++++++ .../crud/aggregate-merge-errorResponse.json | 90 ++++++++++++ .../crud/bulkWrite-errorResponse.json | 87 ++++++++++++ .../crud/deleteOne-errorResponse.json | 81 +++++++++++ .../crud/distinct-comment.json | 12 +- .../crud/findOneAndUpdate-errorResponse.json | 132 ++++++++++++++++++ .../crud/insertOne-errorResponse.json | 81 +++++++++++ .../crud/updateOne-errorResponse.json | 86 ++++++++++++ .../expectedError-errorResponse.json | 70 ++++++++++ 13 files changed, 781 insertions(+), 5 deletions(-) create mode 100644 tests/UnifiedSpecTests/collection-management/modifyCollection-errorResponse.json create mode 100644 tests/UnifiedSpecTests/crud/aggregate-merge-errorResponse.json create mode 100644 tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json create mode 100644 tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json create mode 100644 tests/UnifiedSpecTests/crud/findOneAndUpdate-errorResponse.json create mode 100644 tests/UnifiedSpecTests/crud/insertOne-errorResponse.json create mode 100644 tests/UnifiedSpecTests/crud/updateOne-errorResponse.json create mode 100644 tests/UnifiedSpecTests/valid-pass/expectedError-errorResponse.json diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index bb55b3c4f..b99a9f2ac 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -7,6 +7,7 @@ use MongoDB\Driver\Exception\ExecutionTimeoutException; use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\Exception\ServerException; +use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use PHPUnit\Framework\Assert; use stdClass; use Throwable; @@ -19,6 +20,7 @@ use function PHPUnit\Framework\assertIsArray; use function PHPUnit\Framework\assertIsBool; use function PHPUnit\Framework\assertIsInt; +use function PHPUnit\Framework\assertIsObject; use function PHPUnit\Framework\assertIsString; use function PHPUnit\Framework\assertNotInstanceOf; use function PHPUnit\Framework\assertNotNull; @@ -26,6 +28,7 @@ use function PHPUnit\Framework\assertObjectHasAttribute; use function PHPUnit\Framework\assertSame; use function PHPUnit\Framework\assertStringContainsStringIgnoringCase; +use function PHPUnit\Framework\assertThat; use function PHPUnit\Framework\assertTrue; use function property_exists; use function sprintf; @@ -59,6 +62,9 @@ final class ExpectedError /** @var string|null */ private $codeName; + /** @var Matches|null */ + private $matchesResultDocument; + /** @var array */ private $includedLabels = []; @@ -100,6 +106,11 @@ public function __construct(?stdClass $o, EntityMap $entityMap) $this->codeName = $o->errorCodeName; } + if (isset($o->errorResponse)) { + assertIsObject($o->errorResponse); + $this->matchesResultDocument = new Matches($o->errorResponse, $entityMap); + } + if (isset($o->errorLabelsContain)) { assertIsArray($o->errorLabelsContain); assertContainsOnly('string', $o->errorLabelsContain); @@ -154,6 +165,11 @@ public function assert(?Throwable $e = null): void $this->assertCodeName($e); } + if (isset($this->matchesResultDocument)) { + assertInstanceOf(CommandException::class, $e); + assertThat($e->getResultDocument(), $this->matchesResultDocument, 'CommandException result document matches'); + } + if (! empty($this->excludedLabels) || ! empty($this->includedLabels)) { assertInstanceOf(RuntimeException::class, $e); diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 9a4fea23f..cd5a140da 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -65,6 +65,11 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/createEntities-operation: createEntities operation' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/entity-cursor-iterateOnce: iterateOnce' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/matches-lte-operator: special lte matching operator' => 'CSOT is not yet implemented (PHPC-1760)', + // BulkWriteException cannot access server response + 'crud/bulkWrite-errorResponse: bulkWrite operations support errorResponse assertions' => 'BulkWriteException cannot access server response', + 'crud/deleteOne-errorResponse: delete operations support errorResponse assertions' => 'BulkWriteException cannot access server response', + 'crud/insertOne-errorResponse: insert operations support errorResponse assertions' => 'BulkWriteException cannot access server response', + 'crud/updateOne-errorResponse: update operations support errorResponse assertions' => 'BulkWriteException cannot access server response', ]; /** @var UnifiedTestRunner */ diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 008abe89c..1f636dab3 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -64,7 +64,9 @@ final class UnifiedTestRunner public const MIN_SCHEMA_VERSION = '1.0'; - public const MAX_SCHEMA_VERSION = '1.8'; + /* Note: This is necessary to support expectedError.errorResponse from 1.12; + * however, syntax from 1.9, 1.10, and 1.11 has not been implemented. */ + public const MAX_SCHEMA_VERSION = '1.12'; /** @var MongoDB\Client */ private $internalClient; diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 1c0c249e7..3dd6edd81 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -77,7 +77,7 @@ final class Util 'dropCollection' => ['collection', 'session'], 'listCollectionNames' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], 'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'], - 'modifyCollection' => ['collection', 'changeStreamPreAndPostImages'], + 'modifyCollection' => ['collection', 'changeStreamPreAndPostImages', 'index', 'validator'], // Note: commandName is not used by PHP 'runCommand' => ['command', 'session', 'commandName'], ], @@ -86,7 +86,7 @@ final class Util 'bulkWrite' => ['let', 'requests', 'session', 'ordered', 'bypassDocumentValidation', 'comment'], 'createChangeStream' => ['pipeline', 'session', 'fullDocument', 'fullDocumentBeforeChange', 'resumeAfter', 'startAfter', 'startAtOperationTime', 'batchSize', 'collation', 'maxAwaitTimeMS', 'comment', 'showExpandedEvents'], 'createFindCursor' => ['filter', 'session', 'allowDiskUse', 'allowPartialResults', 'batchSize', 'collation', 'comment', 'cursorType', 'hint', 'limit', 'max', 'maxAwaitTimeMS', 'maxScan', 'maxTimeMS', 'min', 'modifiers', 'noCursorTimeout', 'oplogReplay', 'projection', 'returnKey', 'showRecordId', 'skip', 'snapshot', 'sort'], - 'createIndex' => ['keys', 'commitQuorum', 'maxTimeMS', 'name', 'session', 'comment'], + 'createIndex' => ['keys', 'comment', 'commitQuorum', 'maxTimeMS', 'name', 'session', 'unique'], 'dropIndex' => ['name', 'session', 'maxTimeMS', 'comment'], 'count' => ['filter', 'session', 'collation', 'hint', 'limit', 'maxTimeMS', 'skip', 'comment'], 'countDocuments' => ['filter', 'session', 'limit', 'skip', 'collation', 'hint', 'maxTimeMS', 'comment'], diff --git a/tests/UnifiedSpecTests/collection-management/modifyCollection-errorResponse.json b/tests/UnifiedSpecTests/collection-management/modifyCollection-errorResponse.json new file mode 100644 index 000000000..aea71eb08 --- /dev/null +++ b/tests/UnifiedSpecTests/collection-management/modifyCollection-errorResponse.json @@ -0,0 +1,118 @@ +{ + "description": "modifyCollection-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "collMod-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "collMod-tests", + "documents": [ + { + "_id": 1, + "x": 1 + }, + { + "_id": 2, + "x": 1 + } + ] + } + ], + "tests": [ + { + "description": "modifyCollection prepareUnique violations are accessible", + "runOnRequirements": [ + { + "minServerVersion": "5.2" + } + ], + "operations": [ + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + } + } + }, + { + "name": "modifyCollection", + "object": "database0", + "arguments": { + "collection": "test", + "index": { + "keyPattern": { + "x": 1 + }, + "prepareUnique": true + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 3, + "x": 1 + } + }, + "expectError": { + "errorCode": 11000 + } + }, + { + "name": "modifyCollection", + "object": "database0", + "arguments": { + "collection": "test", + "index": { + "keyPattern": { + "x": 1 + }, + "unique": true + } + }, + "expectError": { + "isClientError": false, + "errorCode": 359, + "errorResponse": { + "violations": [ + { + "ids": [ + 1, + 2 + ] + } + ] + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/aggregate-merge-errorResponse.json b/tests/UnifiedSpecTests/crud/aggregate-merge-errorResponse.json new file mode 100644 index 000000000..6c7305fd9 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/aggregate-merge-errorResponse.json @@ -0,0 +1,90 @@ +{ + "description": "aggregate-merge-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": 1 + }, + { + "_id": 2, + "x": 1 + } + ] + } + ], + "tests": [ + { + "description": "aggregate $merge DuplicateKey error is accessible", + "runOnRequirements": [ + { + "minServerVersion": "5.1", + "topologies": [ + "single", + "replicaset" + ] + } + ], + "operations": [ + { + "name": "aggregate", + "object": "database0", + "arguments": { + "pipeline": [ + { + "$documents": [ + { + "_id": 2, + "x": 1 + } + ] + }, + { + "$merge": { + "into": "test", + "whenMatched": "fail" + } + } + ] + }, + "expectError": { + "errorCode": 11000, + "errorResponse": { + "keyPattern": { + "_id": 1 + }, + "keyValue": { + "_id": 2 + } + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json b/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json new file mode 100644 index 000000000..b520f2404 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json @@ -0,0 +1,87 @@ +{ + "description": "bulkWrite-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "tests": [ + { + "description": "bulkWrite operations support errorResponse assertions", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 8 + } + } + } + }, + { + "name": "bulkWrite", + "object": "collection0", + "arguments": { + "requests": [ + { + "insertOne": { + "document": { + "_id": 1 + } + } + } + ] + }, + "expectError": { + "errorCode": 8, + "errorResponse": { + "code": 8 + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json b/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json new file mode 100644 index 000000000..045b27cfc --- /dev/null +++ b/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json @@ -0,0 +1,81 @@ +{ + "description": "deleteOne-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "tests": [ + { + "description": "delete operations support errorResponse assertions", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "delete" + ], + "errorCode": 8 + } + } + } + }, + { + "name": "deleteOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + } + }, + "expectError": { + "errorCode": 8, + "errorResponse": { + "code": 8 + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/distinct-comment.json b/tests/UnifiedSpecTests/crud/distinct-comment.json index 0669d4f30..11bce9ac9 100644 --- a/tests/UnifiedSpecTests/crud/distinct-comment.json +++ b/tests/UnifiedSpecTests/crud/distinct-comment.json @@ -64,7 +64,11 @@ "key": "value" } }, - "expectResult": [ 11, 22, 33 ] + "expectResult": [ + 11, + 22, + 33 + ] } ], "expectEvents": [ @@ -105,7 +109,11 @@ "filter": {}, "comment": "comment" }, - "expectResult": [ 11, 22, 33 ] + "expectResult": [ + 11, + 22, + 33 + ] } ], "expectEvents": [ diff --git a/tests/UnifiedSpecTests/crud/findOneAndUpdate-errorResponse.json b/tests/UnifiedSpecTests/crud/findOneAndUpdate-errorResponse.json new file mode 100644 index 000000000..5023a450f --- /dev/null +++ b/tests/UnifiedSpecTests/crud/findOneAndUpdate-errorResponse.json @@ -0,0 +1,132 @@ +{ + "description": "findOneAndUpdate-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "initialData": [ + { + "collectionName": "test", + "databaseName": "crud-tests", + "documents": [ + { + "_id": 1, + "x": "foo" + } + ] + } + ], + "tests": [ + { + "description": "findOneAndUpdate DuplicateKey error is accessible", + "runOnRequirements": [ + { + "minServerVersion": "4.2" + } + ], + "operations": [ + { + "name": "createIndex", + "object": "collection0", + "arguments": { + "keys": { + "x": 1 + }, + "unique": true + } + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": "foo" + } + }, + "upsert": true + }, + "expectError": { + "errorCode": 11000, + "errorResponse": { + "keyPattern": { + "x": 1 + }, + "keyValue": { + "x": "foo" + } + } + } + } + ] + }, + { + "description": "findOneAndUpdate document validation errInfo is accessible", + "runOnRequirements": [ + { + "minServerVersion": "5.0" + } + ], + "operations": [ + { + "name": "modifyCollection", + "object": "database0", + "arguments": { + "collection": "test", + "validator": { + "x": { + "$type": "string" + } + } + } + }, + { + "name": "findOneAndUpdate", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + }, + "expectError": { + "errorCode": 121, + "errorResponse": { + "errInfo": { + "failingDocumentId": 1, + "details": { + "$$type": "object" + } + } + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json b/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json new file mode 100644 index 000000000..98f8830f6 --- /dev/null +++ b/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json @@ -0,0 +1,81 @@ +{ + "description": "insertOne-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "tests": [ + { + "description": "insert operations support errorResponse assertions", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "insert" + ], + "errorCode": 8 + } + } + } + }, + { + "name": "insertOne", + "object": "collection0", + "arguments": { + "document": { + "_id": 1 + } + }, + "expectError": { + "errorCode": 8, + "errorResponse": { + "code": 8 + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json b/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json new file mode 100644 index 000000000..070d66dcf --- /dev/null +++ b/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json @@ -0,0 +1,86 @@ +{ + "description": "updateOne-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "crud-tests" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "test" + } + } + ], + "tests": [ + { + "description": "update operations support errorResponse assertions", + "runOnRequirements": [ + { + "minServerVersion": "4.0.0", + "topologies": [ + "single", + "replicaset" + ] + }, + { + "minServerVersion": "4.2.0", + "topologies": [ + "sharded" + ] + } + ], + "operations": [ + { + "name": "failPoint", + "object": "testRunner", + "arguments": { + "client": "client0", + "failPoint": { + "configureFailPoint": "failCommand", + "mode": { + "times": 1 + }, + "data": { + "failCommands": [ + "update" + ], + "errorCode": 8 + } + } + } + }, + { + "name": "updateOne", + "object": "collection0", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + }, + "expectError": { + "errorCode": 8, + "errorResponse": { + "code": 8 + } + } + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/valid-pass/expectedError-errorResponse.json b/tests/UnifiedSpecTests/valid-pass/expectedError-errorResponse.json new file mode 100644 index 000000000..177b1baf5 --- /dev/null +++ b/tests/UnifiedSpecTests/valid-pass/expectedError-errorResponse.json @@ -0,0 +1,70 @@ +{ + "description": "expectedError-errorResponse", + "schemaVersion": "1.12", + "createEntities": [ + { + "client": { + "id": "client0" + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "coll0" + } + } + ], + "tests": [ + { + "description": "Unsupported command", + "operations": [ + { + "name": "runCommand", + "object": "database0", + "arguments": { + "commandName": "unsupportedCommand", + "command": { + "unsupportedCommand": 1 + } + }, + "expectError": { + "errorResponse": { + "errmsg": { + "$$type": "string" + } + } + } + } + ] + }, + { + "description": "Unsupported query operator", + "operations": [ + { + "name": "find", + "object": "collection0", + "arguments": { + "filter": { + "$unsupportedQueryOperator": 1 + } + }, + "expectError": { + "errorResponse": { + "errmsg": { + "$$type": "string" + } + } + } + } + ] + } + ] +} From 7b3eca3efb522b60f4132f2688a8ab4494f45831 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Mon, 24 Oct 2022 08:54:23 +0200 Subject: [PATCH 220/321] PHPLIB-986: Split keyAltName example and link key management docs (#995) * PHPLIB-986: Split keyAltName example and link key management docs * Apply grammar suggestions * Move key creation to top of csfle tutorial * Apply suggestions from code review Co-authored-by: Jeremy Mikola Co-authored-by: Jeremy Mikola --- docs/tutorial/client-side-encryption.txt | 103 +++++++++++++++-------- 1 file changed, 70 insertions(+), 33 deletions(-) diff --git a/docs/tutorial/client-side-encryption.txt b/docs/tutorial/client-side-encryption.txt index 6ed2e00d4..10a3a56ca 100644 --- a/docs/tutorial/client-side-encryption.txt +++ b/docs/tutorial/client-side-encryption.txt @@ -14,6 +14,50 @@ Client-Side Field Level Encryption allows administrators and developers to encrypt specific data fields in addition to other MongoDB encryption features. +Creating an Encryption Key +-------------------------- + +.. note:: + + The following examples use a local master key; however, other key providers + such as AWS KMS are also an option. This master key is used to encrypt data + keys that are stored locally. It is important that you keep this key secure. + +To create an encryption key, create a :php:`MongoDB\\Driver\\ClientEncryption ` +instance with encryption options and create a new data key. The method will +return the key ID which can be used to reference the key later. You can also +pass multiple alternate names for this key and reference the key by these names +instead of the key ID. Creating a new data encryption key would typically be +done on initial deployment, but depending on your use case you may want to use +more than one encryption key or create them dynamically. + +.. code-block:: php + + ', Binary::TYPE_GENERIC); + + $clientEncryptionOpts = [ + 'keyVaultNamespace' => 'encryption.__keyVault', + 'kmsProviders' => [ + 'local' => ['key' => $localKey], + ], + ]; + + $client = new Client(); + $clientEncryption = $client->createClientEncryption($clientEncryptionOpts); + + // Create an encryption key with an alternate name + // To store the key ID for later use, you can use serialize or var_export + $keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['my-encryption-key']]); + +.. seealso:: :manual:`Encryption Key Management ` in the MongoDB manual + + Automatic Encryption and Decryption ----------------------------------- @@ -21,9 +65,10 @@ Automatic Encryption and Decryption Auto encryption is an enterprise only feature. -The following example uses a local key; however, other key providers such as AWS -are also an option. The data in the ``encryptedField`` field is automatically -encrypted on insertion and decrypted when querying on the client side. +The following example sets up a collection with automatic encryption based on a +``$jsonSchema`` validator. The data in the ``encryptedField`` field is +automatically encrypted on insertion and decrypted when reading on the client +side. .. code-block:: php @@ -34,7 +79,6 @@ encrypted on insertion and decrypted when querying on the client side. use MongoDB\Driver\ClientEncryption; $localKey = new Binary('', Binary::TYPE_GENERIC); - $encryptionOpts = [ 'keyVaultNamespace' => 'encryption.__keyVault', 'kmsProviders' => [ @@ -43,13 +87,13 @@ encrypted on insertion and decrypted when querying on the client side. ]; $client = new Client(); - $clientEncryption = $client->createClientEncryption($encryptionOpts); $database = $client->selectDatabase('test'); $database->dropCollection('coll'); // remove old data - // Create new key in the key vault and store its ID for later use - $keyId = $clientEncryption->createDataKey('local'); + // This uses the key ID from the first example. The key ID could be read from + // a configuration file. + $keyId = readDataKey(); $database->createCollection('coll', [ 'validator' => [ @@ -80,9 +124,8 @@ encrypted on insertion and decrypted when querying on the client side. Specifying an Explicit Schema for Encryption -------------------------------------------- -The following example shows how to create a new key and store it in the key -vault collection. The encrypted client configures an explicit schema for -encryption using the newly created key. +The following example uses the ``schemaMap`` encryption option to define +encrypted fields. .. note:: @@ -101,18 +144,11 @@ encryption using the newly created key. $localKey = new Binary('', Binary::TYPE_GENERIC); - $clientEncryptionOpts = [ - 'keyVaultNamespace' => 'encryption.__keyVault', - 'kmsProviders' => [ - 'local' => ['key' => $localKey], - ], - ]; - $client = new Client(); - $clientEncryption = $client->createClientEncryption($clientEncryptionOpts); - // Create new key in the key vault and store its ID for later use - $keyId = $clientEncryption->createDataKey('local'); + // This uses the key ID from the first example. The key ID could be read from + // a configuration file. + $keyId = readDataKey(); $autoEncryptionOpts = [ 'keyVaultNamespace' => 'encryption.__keyVault', @@ -148,10 +184,10 @@ encryption using the newly created key. Manually Encrypting and Decrypting Values ----------------------------------------- -In the MongoDB Community Edition, you will have to manually encrypt and decrypt -values before storing them in the database. The following example assumes that -you have already created an encryption key in the key vault collection and -explicitly encrypts and decrypts values in the document. +In the MongoDB Community Edition, you will have to manually encrypt values +before storing them in the database. The following example assumes that you have +already created an encryption key in the key vault collection and explicitly +encrypts and decrypts values in the document. .. code-block:: php @@ -173,8 +209,9 @@ explicitly encrypts and decrypts values in the document. $client = new Client(); $clientEncryption = $client->createClientEncryption($clientEncryptionOpts); - // Create new key in the key vault and store its ID for later use - $keyId = $clientEncryption->createDataKey('local'); + // This uses the key ID from the first example. The key ID could be read from + // a configuration file. + $keyId = readDataKey(); $collection = $client->selectCollection('test', 'coll'); $collection->drop(); // clear old data @@ -196,12 +233,15 @@ Referencing Encryption Keys by an Alternative Name While it is possible to create an encryption key every time data is encrypted, this is not the recommended approach. Instead, you should create your encryption -keys depending on your use-case, e.g. by creating a user-specific encryption +keys depending on your use case, e.g. by creating a user-specific encryption key. To reference keys in your software, you can use the keyAltName attribute specified when creating the key. The following example creates an encryption key with an alternative name, which could be done when deploying the application. The software then encrypts data by referencing the key by its alternative name. +To use an alternate name when referencing an encryption key, use the +``keyAltName`` option instead of ``keyId``. + .. code-block:: php createClientEncryption($clientEncryptionOpts); - // Create an encryption key with an alternative name. This could be done when - // deploying the application - $keyId = $clientEncryption->createDataKey('local', ['keyAltNames' => ['altname']]); - $collection = $client->selectCollection('test', 'coll'); $collection->drop(); // clear old data - // Reference the encryption key we created earlier by its alternative name + // Reference the encryption key created in the first example by its + // alternative name $encryptionOpts = [ - 'keyAltName' => 'altname', + 'keyAltName' => 'my-encryption-key', 'algorithm' => ClientEncryption::AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, ]; $encryptedValue = $clientEncryption->encrypt('123456789', $encryptionOpts); From 56e8a05352549263042bf0f647ba648f3e3e8e00 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 25 Oct 2022 08:10:05 +0200 Subject: [PATCH 221/321] PHPLIB-572: Add debugging tools (#996) * Add connection debugging script * Fix grammar * Add extension detection script * Fix wording feedback * Document using pre tags for formatted output in web SAPI --- docs/faq.txt | 46 ++++++++++++- phpcs.xml.dist | 1 + tools/connect.php | 137 +++++++++++++++++++++++++++++++++++++ tools/detect-extension.php | 98 ++++++++++++++++++++++++++ 4 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 tools/connect.php create mode 100644 tools/detect-extension.php diff --git a/docs/faq.txt b/docs/faq.txt index ec541a820..ff9acc025 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -53,6 +53,25 @@ SAPI. Additionally, :php:`php_ini_loaded_file() ` and :php:`php_ini_scanned_files() ` may be used to determine exactly which INI files have been loaded by PHP. +To debug issues with the extension not being loaded, you can use the +``detect-extension`` script provided in the tools directory. You can run this +script from the CLI or include it in a script accessible via your web server. +The tool will point out potential issues and installation instructions for your +system. Assuming you've installed the library through Composer, you can call the +script from the vendor directory: + +.. code-block:: none + + php vendor/mongodb/mongodb/tools/detect-extension.php + +If you want to check configuration for a web server SAPI, include the file in +a script accessible from the web server and open it in your browser. Remember to +wrap the script in ``
`` tags to properly format its output:
+
+.. code-block:: php
+
+   
+ Loading an Incompatible DLL on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -80,7 +99,7 @@ for the correct environment. Server Selection Failures ------------------------- -The follow are all examples of +The following are all examples of :doc:`Server Selection ` failures: .. code-block:: none @@ -133,3 +152,28 @@ failure: but was dropped or otherwise timeout out due to latency. - "TLS handshake failed" suggests something related to TLS or OCSP verification and is sometimes indicative of misconfigured TLS certificates. + +In the case of a connection failure, you can use the ``connect`` tool to try and +receive more information. This tool attempts to connect to each host in a +connection string using socket functions to see if it is able to establish a +connection, send, and receive data. The tool takes the connection string to a +MongoDB deployment as its only argument. Assuming you've installed the library +through Composer, you would call the script from the vendor directory: + +.. code-block:: none + + php vendor/mongodb/mongodb/tools/connect.php mongodb://127.0.0.1:27017 + +In case the server does not accept connections, the output will look like this: + +.. code-block:: none + + Looking up MongoDB at mongodb://127.0.0.1:27017 + Found 1 host(s) in the URI. Will attempt to connect to each. + + Could not connect to 127.0.0.1:27017: Connection refused + +.. note:: + + The tool only supports the ``mongodb://`` URI schema. Using the + ``mongodb+srv`` scheme is not supported. diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 7db7074b7..a2d56ccce 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -12,6 +12,7 @@ src examples tests + tools diff --git a/tools/connect.php b/tools/connect.php new file mode 100644 index 000000000..121f727c7 --- /dev/null +++ b/tools/connect.php @@ -0,0 +1,137 @@ + ['capture_peer_cert' => true]] : []); + $client = @stream_socket_client($uri, $errno, $errorMessage, 5, STREAM_CLIENT_CONNECT, $context); + + if ($client === false) { + printf("Could not connect to %s: %s\n", $host, $errorMessage); + + return; + } + + if ($ssl) { + $peerCertificate = stream_context_get_params($client)['options']['ssl']['peer_certificate'] ?? null; + + if (! isset($peerCertificate)) { + printf("Could not capture peer certificate for %s\n", $host); + + return; + } + + $certificateProperties = openssl_x509_parse($peerCertificate); + + // TODO: Check that the certificate common name (CN) matches the hostname + $now = new DateTime(); + $validFrom = DateTime::createFromFormat('U', $certificateProperties['validFrom_time_t']); + $validTo = DateTime::createFromFormat('U', $certificateProperties['validTo_time_t']); + $isValid = $now >= $validFrom && $now <= $validTo; + + printf("Peer certificate for %s is %s\n", $host, $isValid ? 'valid' : 'expired'); + + if (! $isValid) { + printf(" Valid from %s to %s\n", $validFrom->format('c'), $validTo->format('c')); + } + } + + $request = pack( + 'Va*xVVa*', + 1 << 2 /* slaveOk */, + 'admin.$cmd', /* namespace */ + 0, /* numberToSkip */ + 1, /* numberToReturn */ + hex2bin('130000001069734d6173746572000100000000') /* { "isMaster": 1 } */ + ); + $requestLength = 16 /* MsgHeader length */ + strlen($request); + $header = pack('V4', $requestLength, 0 /* requestID */, 0 /* responseTo */, 2004 /* OP_QUERY */); + + if ($requestLength !== streamWrite($client, $header . $request)) { + printf("Could not write request to %s\n", $host); + + return; + } + + $data = streamRead($client, 4); + + if ($data === false || strlen($data) !== 4) { + printf("Could not read response header from %s\n", $host); + + return; + } + + [, $responseLength] = unpack('V', $data); + + $data = streamRead($client, $responseLength - 4); + + if ($data === false || strlen($data) !== $responseLength - 4) { + printf("Could not read response from %s\n", $host); + + return; + } + + printf("Successfully received response from %s\n", $host); +} + +$uri = $argv[1] ?? 'mongodb://127.0.0.1'; +printf("Looking up MongoDB at %s\n", $uri); +$hosts = getHosts($uri); +$ssl = stripos(parse_url($uri, PHP_URL_QUERY) ?? '', 'ssl=true') !== false; + +printf("Found %d host(s) in the URI. Will attempt to connect to each.\n", count($hosts)); + +foreach ($hosts as $host) { + echo "\n"; + connect($host, $ssl); +} diff --git a/tools/detect-extension.php b/tools/detect-extension.php new file mode 100644 index 000000000..4b599fd4b --- /dev/null +++ b/tools/detect-extension.php @@ -0,0 +1,98 @@ + $line) { + if (strpos($line, 'extension') === false) { + continue; + } + + if (strpos($line, $extension) === false) { + continue; + } + + $lines[$i] = $line; + } + + if (empty($lines)) { + printf("No interesting lines in %s.\n", $filename); + + return 0; + } + + printf("Interesting lines in %s...\n", $filename); + foreach ($lines as $i => $line) { + printf(" %d: %s\n", $i + 1, trim($line)); + } + + return count($lines); +} + +$extension = $argv[1] ?? 'mongodb'; +$extensionDir = ini_get('extension_dir'); + +$version = phpversion($extension); + +if ($version !== false) { + printf("Extension \"%s\" is loaded. Version: %s\n", $extension, $version); + exit; +} + +printf("Extension \"%s\" is not loaded. Will attempt to scan INI files.\n", $extension); + +// Check main INI file +$ini = php_ini_loaded_file(); +$lines = 0; + +if ($ini === false) { + printf("No php.ini file is loaded. Will attempt to scan additional INI files.\n"); +} else { + $lines += grepIniFile($ini, $extension); +} + +// Check additional INI files in scan directory +// See: https://www.php.net/manual/en/configuration.file.php#configuration.file.scan +$files = php_ini_scanned_files(); + +if (empty($files)) { + printf("No additional INI files are loaded. Nothing left to scan.\n"); +} else { + foreach (explode(',', $files) as $ini) { + $lines += grepIniFile(trim($ini), $extension); + } +} + +$mask = defined('PHP_WINDOWS_VERSION_BUILD') ? 'php_%s.dll' : '%s.so'; +$filename = sprintf($mask, $extension); +$extensionFileExists = file_exists($extensionDir . '/' . $filename); + +echo "\n"; +printf("PHP will look for extensions in: %s\n", $extensionDir); +printf("Checking if that directory is readable: %s\n", is_dir($extensionDir) || ! is_readable($extensionDir) ? 'yes' : 'no'); +printf("Checking if extension file exists in that directory: %s\n", $extensionFileExists ? 'yes' : 'no'); +echo "\n"; + +if ($extensionFileExists) { + printf("A file named %s exists in the extension directory. Make sure you have enabled the extension in php.ini.\n", $filename); +} elseif (! defined('PHP_WINDOWS_VERSION_BUILD')) { + // Installation instructions for non-Windows systems are only necessary if the extension file does not exist. + printf("You should install the extension using the pecl command in %s\n", PHP_BINDIR); + printf("After installing the extension, you should add \"extension=%s\" to php.ini\n", $filename); +} + +if (defined('PHP_WINDOWS_VERSION_BUILD')) { + $zts = PHP_ZTS ? 'Thread Safe (TS)' : 'Non Thread Safe (NTS)'; + $arch = PHP_INT_SIZE === 8 ? 'x64' : 'x86'; + $dll = sprintf("%d.%d %s %s", PHP_MAJOR_VERSION, PHP_MINOR_VERSION, $zts, $arch); + + printf("You likely need to download a Windows DLL for: %s\n", $dll); + printf("Windows DLLs should be available from: https://pecl.php.net/package/%s\n", $extension); + + if ($extensionFileExists) { + echo "If you have enabled the extension in php.ini and it is not loading, make sure you have downloaded the correct DLL file as indicated above.\n"; + } else { + printf("After installing the extension, you should add \"extension=%s\" to php.ini\n", $filename); + } +} From 1a4eed862fd3080d53a47caad35751c8556ccfd2 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 25 Oct 2022 08:10:42 +0200 Subject: [PATCH 222/321] PHPLIB-1023: Provide OS variant when building mongohoused (#997) * PHPLIB-1023: Provide OS variant when building mongohoused This resolves error with our go config * Update .evergreen/config.yml Co-authored-by: Jeremy Mikola Co-authored-by: Jeremy Mikola --- .evergreen/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 9d831b017..e4530bc0c 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -192,7 +192,7 @@ functions: - command: shell.exec params: script: | - DRIVERS_TOOLS="${DRIVERS_TOOLS}" sh ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/build-mongohouse-local.sh + VARIANT=${VARIANT} DRIVERS_TOOLS="${DRIVERS_TOOLS}" sh ${DRIVERS_TOOLS}/.evergreen/atlas_data_lake/build-mongohouse-local.sh - command: shell.exec params: background: true @@ -834,6 +834,8 @@ buildvariants: matrix_spec: { "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } display_name: "Atlas Data Lake" run_on: debian11 + expansions: + VARIANT: debian11 # Referenced by ADL build script for downloading MQLRun tasks: - name: "test-atlas-data-lake" From 5a3d371dc5f3c212f907c345a2520eaa3303d1b8 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Sun, 30 Oct 2022 22:34:10 +0800 Subject: [PATCH 223/321] PHPLIB-909: Update errorResponse tests (#998) Synced with mongodb/specifications@c04f2ec111ec0e5c9cfd46e37a91ea2f3c63f0f5 --- tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json | 3 ++- tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json | 3 ++- tests/UnifiedSpecTests/crud/insertOne-errorResponse.json | 3 ++- tests/UnifiedSpecTests/crud/updateOne-errorResponse.json | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json b/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json index b520f2404..157637c71 100644 --- a/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json +++ b/tests/UnifiedSpecTests/crud/bulkWrite-errorResponse.json @@ -4,7 +4,8 @@ "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "useMultipleMongoses": false } }, { diff --git a/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json b/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json index 045b27cfc..1f3a266f1 100644 --- a/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json +++ b/tests/UnifiedSpecTests/crud/deleteOne-errorResponse.json @@ -4,7 +4,8 @@ "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "useMultipleMongoses": false } }, { diff --git a/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json b/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json index 98f8830f6..04ea6a745 100644 --- a/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json +++ b/tests/UnifiedSpecTests/crud/insertOne-errorResponse.json @@ -4,7 +4,8 @@ "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "useMultipleMongoses": false } }, { diff --git a/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json b/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json index 070d66dcf..0ceddbc4f 100644 --- a/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json +++ b/tests/UnifiedSpecTests/crud/updateOne-errorResponse.json @@ -4,7 +4,8 @@ "createEntities": [ { "client": { - "id": "client0" + "id": "client0", + "useMultipleMongoses": false } }, { From a7b1567472680af3f6cc43bba062dea9bfb9ab1c Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 1 Nov 2022 21:55:35 +0800 Subject: [PATCH 224/321] PHPLIB-951: Assert operation before argument validation (#999) This prevents a potential PHP warning for accessing a nonexistent array key if the operation doesn't exist, which was responsible for some Astrolabe test failures. Since assertArgumentsBySchema() is called before the switch statement in Operation execute methods, we don't yet know that the operation exists. With this change, we should never hit default cases in those switch statements; however, they can remain in place for now. --- tests/UnifiedSpecTests/Util.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php index 3dd6edd81..d9b3b3898 100644 --- a/tests/UnifiedSpecTests/Util.php +++ b/tests/UnifiedSpecTests/Util.php @@ -20,6 +20,7 @@ use function array_key_exists; use function array_keys; use function implode; +use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertContains; use function PHPUnit\Framework\assertEmpty; use function PHPUnit\Framework\assertIsArray; @@ -141,6 +142,8 @@ public static function assertHasOnlyKeys($arrayOrObject, array $keys): void public static function assertArgumentsBySchema(string $executingObjectName, string $operation, array $args): void { + assertArrayHasKey($executingObjectName, self::$args); + assertArrayHasKey($operation, self::$args[$executingObjectName]); self::assertHasOnlyKeys($args, self::$args[$executingObjectName][$operation]); } From 306739d255fa4f560d46a96caad7f77dc9a9ae5d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 2 Nov 2022 12:49:39 +0800 Subject: [PATCH 225/321] PHPLIB-1024: Add PHP 8.2 to Evergreen matrix (#1000) --- .evergreen/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index e4530bc0c..8171e22d8 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -607,6 +607,10 @@ axes: - id: php-versions display_name: PHP Version values: + - id: "8.2" + display_name: "PHP 8.2" + variables: + PHP_VERSION: "8.2" - id: "8.1" display_name: "PHP 8.1" variables: From 035d367d3c2ea102dd841c667318859171902578 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 3 Nov 2022 12:53:40 +0800 Subject: [PATCH 226/321] PHPLIB-1037: Ensure EntityMap is set before invoking observer callable (#1001) This handles the case where a test fails prior to Context initialization (e.g. while populating initial data). --- tests/UnifiedSpecTests/UnifiedTestRunner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 1f636dab3..668eec997 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -125,7 +125,7 @@ public function run(UnifiedTestCase $test): void * succeeding or failing. Since the callable itself might throw, we * need to ensure doTearDown() will still be called. */ try { - if (isset($this->entityMapObserver)) { + if (isset($this->entityMapObserver, $this->entityMap)) { call_user_func($this->entityMapObserver, $this->entityMap); } } finally { From b309cf8e4deb784705543addace0959ad13c0afc Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 22 Nov 2022 10:23:06 +0100 Subject: [PATCH 227/321] PHPLIB-981: Add tests for examples (#1002) * No longer print to STDERR * PHPLIB-981: Test example scripts * Relax command/reply assertions * Create test collection in transaction example to avoid errors on MongoDB <= 4.2 * Update command logger test output to handle collection differences On sharded cluster, collection deletion is sometimes not propagated across the cluster, leading to different output even if we drop the collection before the test. * Create test collection in change stream example * Use majority write concern in bulk example * Fix psalm errors * Use different collection names in each example This should help reduce test failures * Skip example tests on sharded clusters * Update psalm-baseline on PHP 7.4 * Update collection names in tests Co-authored-by: Jeremy Mikola * Exclude bulk write psalm error Fixing this requires a larger-scale refactoring of the types involved, which was deferred to a later date. Co-authored-by: Jeremy Mikola --- examples/aggregate.php | 2 +- examples/bulk.php | 5 +- examples/changestream.php | 10 +- examples/command_logger.php | 29 +++-- examples/persistable.php | 2 +- examples/typemap.php | 2 +- examples/with_transaction.php | 5 +- psalm-baseline.xml | 45 +++++++- tests/ExamplesTest.php | 198 ++++++++++++++++++++++++++++++++++ 9 files changed, 269 insertions(+), 29 deletions(-) create mode 100644 tests/ExamplesTest.php diff --git a/examples/aggregate.php b/examples/aggregate.php index 9a4873593..7f9da6cc3 100644 --- a/examples/aggregate.php +++ b/examples/aggregate.php @@ -22,7 +22,7 @@ function toJSON(object $document): string $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$collection = $client->test->coll; +$collection = $client->test->aggregate; $collection->drop(); $documents = []; diff --git a/examples/bulk.php b/examples/bulk.php index 1af53f755..316594f00 100644 --- a/examples/bulk.php +++ b/examples/bulk.php @@ -4,6 +4,7 @@ namespace MongoDB\Examples; use MongoDB\Client; +use MongoDB\Driver\WriteConcern; use function assert; use function getenv; @@ -21,7 +22,7 @@ function toJSON(object $document): string $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$collection = $client->test->coll; +$collection = $client->test->bulk; $collection->drop(); $documents = []; @@ -30,7 +31,7 @@ function toJSON(object $document): string $documents[] = ['x' => $i]; } -$collection->insertMany($documents); +$collection->insertMany($documents, ['writeConcern' => new WriteConcern('majority')]); $collection->bulkWrite( [ diff --git a/examples/changestream.php b/examples/changestream.php index b54be8ff2..8c871f59c 100644 --- a/examples/changestream.php +++ b/examples/changestream.php @@ -6,7 +6,6 @@ use MongoDB\Client; use function assert; -use function fprintf; use function getenv; use function is_object; use function MongoDB\BSON\fromPHP; @@ -14,8 +13,6 @@ use function printf; use function time; -use const STDERR; - require __DIR__ . '/../vendor/autoload.php'; function toJSON(object $document): string @@ -26,9 +23,12 @@ function toJSON(object $document): string // Change streams require a replica set or sharded cluster $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$collection = $client->test->coll; +$collection = $client->test->changestream; $collection->drop(); +// Create collection before starting change stream; this is required on MongoDB 3.6 +$client->test->createCollection('changestream'); + $changeStream = $collection->watch(); $documents = []; @@ -53,7 +53,7 @@ function toJSON(object $document): string $changeStream->next(); if (time() - $startTime > 3) { - fprintf(STDERR, "Aborting after 3 seconds...\n"); + printf("Aborting after 3 seconds...\n"); break; } } diff --git a/examples/command_logger.php b/examples/command_logger.php index 7eab169bf..9d3f7c0fe 100644 --- a/examples/command_logger.php +++ b/examples/command_logger.php @@ -10,7 +10,6 @@ use MongoDB\Driver\Monitoring\CommandSucceededEvent; use function assert; -use function fprintf; use function get_class; use function getenv; use function is_object; @@ -18,8 +17,6 @@ use function MongoDB\BSON\toRelaxedExtendedJSON; use function printf; -use const STDERR; - require __DIR__ . '/../vendor/autoload.php'; function toJSON(object $document): string @@ -31,29 +28,29 @@ class CommandLogger implements CommandSubscriber { public function commandStarted(CommandStartedEvent $event): void { - fprintf(STDERR, "%s command started\n", $event->getCommandName()); + printf("%s command started\n", $event->getCommandName()); - fprintf(STDERR, "command: %s\n", toJson($event->getCommand())); - fprintf(STDERR, "\n"); + printf("command: %s\n", toJson($event->getCommand())); + printf("\n"); } public function commandSucceeded(CommandSucceededEvent $event): void { - fprintf(STDERR, "%s command succeeded\n", $event->getCommandName()); - fprintf(STDERR, "reply: %s\n", toJson($event->getReply())); - fprintf(STDERR, "\n"); + printf("%s command succeeded\n", $event->getCommandName()); + printf("reply: %s\n", toJson($event->getReply())); + printf("\n"); } public function commandFailed(CommandFailedEvent $event): void { - fprintf(STDERR, "%s command failed\n", $event->getCommandName()); - fprintf(STDERR, "reply: %s\n", toJson($event->getReply())); + printf("%s command failed\n", $event->getCommandName()); + printf("reply: %s\n", toJson($event->getReply())); $exception = $event->getError(); - fprintf(STDERR, "exception: %s\n", get_class($exception)); - fprintf(STDERR, "exception.code: %d\n", $exception->getCode()); - fprintf(STDERR, "exception.message: %s\n", $exception->getMessage()); - fprintf(STDERR, "\n"); + printf("exception: %s\n", get_class($exception)); + printf("exception.code: %d\n", $exception->getCode()); + printf("exception.message: %s\n", $exception->getMessage()); + printf("\n"); } } @@ -61,7 +58,7 @@ public function commandFailed(CommandFailedEvent $event): void $client->getManager()->addSubscriber(new CommandLogger()); -$collection = $client->test->coll; +$collection = $client->test->command_logger; $collection->drop(); $collection->insertMany([ diff --git a/examples/persistable.php b/examples/persistable.php index f41cc54b3..e4a5c95e9 100644 --- a/examples/persistable.php +++ b/examples/persistable.php @@ -98,7 +98,7 @@ public function bsonUnserialize(array $data): void $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$collection = $client->test->coll; +$collection = $client->test->persistable; $collection->drop(); $collection->insertOne($entry); diff --git a/examples/typemap.php b/examples/typemap.php index 02d222e01..51097bc90 100644 --- a/examples/typemap.php +++ b/examples/typemap.php @@ -93,7 +93,7 @@ public function bsonUnserialize(array $data): void $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$collection = $client->test->coll; +$collection = $client->test->typemap; $collection->drop(); $document = [ diff --git a/examples/with_transaction.php b/examples/with_transaction.php index a30a9ab2b..15eba6524 100644 --- a/examples/with_transaction.php +++ b/examples/with_transaction.php @@ -24,9 +24,12 @@ function toJSON(object $document): string // Transactions require a replica set (MongoDB >= 4.0) or sharded cluster (MongoDB >= 4.2) $client = new Client(getenv('MONGODB_URI') ?: 'mongodb://127.0.0.1/'); -$collection = $client->test->coll; +$collection = $client->test->with_transaction; $collection->drop(); +// Create collection outside of transaction; this is required when using MongoDB < 4.4 +$client->test->createCollection('with_transaction'); + $insertData = function (Session $session) use ($collection): void { $collection->insertMany( [ diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 179ce8c12..276f9370e 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,5 +1,37 @@ - + + + + string + + + toRelaxedExtendedJSON(fromPHP($document)) + + + + + string + + + toRelaxedExtendedJSON(fromPHP($document)) + + + + + string + + + toRelaxedExtendedJSON(fromPHP($document)) + + + + + string + + + toRelaxedExtendedJSON(fromPHP($document)) + + $address @@ -9,6 +41,14 @@ $type + + + string + + + toRelaxedExtendedJSON(fromPHP($document)) + + $driverOptions['driver'] ?? [] @@ -357,7 +397,8 @@ $args[1] $args[2] - + + $args[0] $args[0] $args[0] $args[0] diff --git a/tests/ExamplesTest.php b/tests/ExamplesTest.php new file mode 100644 index 000000000..d90f53dd6 --- /dev/null +++ b/tests/ExamplesTest.php @@ -0,0 +1,198 @@ +isShardedCluster()) { + $this->markTestSkipped('Examples are not tested on sharded clusters.'); + } + + self::createTestClient()->dropDatabase('test'); + } + + public function dataExamples(): Generator + { + $expectedOutput = <<<'OUTPUT' +{ "_id" : null, "totalCount" : 100, "evenCount" : %d, "oddCount" : %d, "maxValue" : %d, "minValue" : %d } +OUTPUT; + + yield 'aggregate' => [ + 'file' => __DIR__ . '/../examples/aggregate.php', + 'expectedOutput' => $expectedOutput, + ]; + + $expectedOutput = <<<'OUTPUT' +%s +%s +%s +%s +%s +%s +%s +%s +OUTPUT; + + yield 'bulk' => [ + 'file' => __DIR__ . '/../examples/bulk.php', + 'expectedOutput' => $expectedOutput, + ]; + + $expectedOutput = <<<'OUTPUT' +drop command started +command: %s + +drop command %a + +insert command started +command: %s + +insert command succeeded +reply: %s + +update command started +command: %s + +update command succeeded +reply: %s + +find command started +command: %s + +find command succeeded +reply: %s + +%s +%s +getMore command started +command: %s + +getMore command succeeded +reply: %s + +%s +OUTPUT; + + yield 'command_logger' => [ + 'file' => __DIR__ . '/../examples/command_logger.php', + 'expectedOutput' => $expectedOutput, + ]; + + $expectedOutput = <<<'OUTPUT' +object(MongoDB\Examples\PersistableEntry)#%d (%d) { + ["id":"MongoDB\Examples\PersistableEntry":private]=> + object(MongoDB\BSON\ObjectId)#%d (%d) { + ["oid"]=> + string(24) "%s" + } + ["name"]=> + string(7) "alcaeus" + ["emails"]=> + array(2) { + [0]=> + object(MongoDB\Examples\PersistableEmail)#%d (%d) { + ["type"]=> + string(4) "work" + ["address"]=> + string(19) "alcaeus@example.com" + } + [1]=> + object(MongoDB\Examples\PersistableEmail)#%d (%d) { + ["type"]=> + string(7) "private" + ["address"]=> + string(18) "secret@example.com" + } + } +} +OUTPUT; + + yield 'persistable' => [ + 'file' => __DIR__ . '/../examples/persistable.php', + 'expectedOutput' => $expectedOutput, + ]; + + $expectedOutput = <<<'OUTPUT' +object(MongoDB\Examples\TypeMapEntry)#%d (%d) { + ["id":"MongoDB\Examples\TypeMapEntry":private]=> + object(MongoDB\BSON\ObjectId)#%d (%d) { + ["oid"]=> + string(24) "%s" + } + ["name":"MongoDB\Examples\TypeMapEntry":private]=> + string(7) "alcaeus" + ["emails":"MongoDB\Examples\TypeMapEntry":private]=> + array(2) { + [0]=> + object(MongoDB\Examples\TypeMapEmail)#%d (%d) { + ["type":"MongoDB\Examples\TypeMapEmail":private]=> + string(4) "work" + ["address":"MongoDB\Examples\TypeMapEmail":private]=> + string(19) "alcaeus@example.com" + } + [1]=> + object(MongoDB\Examples\TypeMapEmail)#%d (%d) { + ["type":"MongoDB\Examples\TypeMapEmail":private]=> + string(7) "private" + ["address":"MongoDB\Examples\TypeMapEmail":private]=> + string(18) "secret@example.com" + } + } +} +OUTPUT; + + yield 'typemap' => [ + 'file' => __DIR__ . '/../examples/typemap.php', + 'expectedOutput' => $expectedOutput, + ]; + } + + public function testChangeStream(): void + { + $this->skipIfChangeStreamIsNotSupported(); + + $expectedOutput = <<<'OUTPUT' +%s +%s +%s +%s +%s +%s +%s +%s +%s +%s +Aborting after 3 seconds... +OUTPUT; + + $this->testExample(__DIR__ . '/../examples/changestream.php', $expectedOutput); + } + + /** @dataProvider dataExamples */ + public function testExample(string $file, string $expectedOutput): void + { + require $file; + + self::assertStringMatchesFormat($expectedOutput, $this->getActualOutputForAssertion()); + } + + public function testWithTransaction(): void + { + $this->skipIfTransactionsAreNotSupported(); + + $expectedOutput = <<<'OUTPUT' +%s +%s +%s +OUTPUT; + + $this->testExample(__DIR__ . '/../examples/with_transaction.php', $expectedOutput); + } +} From 818520c7f5fc325b4d9166c56371b7e955fce7c3 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 22 Nov 2022 18:03:57 +0800 Subject: [PATCH 228/321] PHPLIB-1040: Demonstrate enum handling in BSON tutorial (#1004) --- docs/tutorial/modeling-bson-data.txt | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/docs/tutorial/modeling-bson-data.txt b/docs/tutorial/modeling-bson-data.txt index 8d2e90064..38f44769f 100644 --- a/docs/tutorial/modeling-bson-data.txt +++ b/docs/tutorial/modeling-bson-data.txt @@ -156,3 +156,60 @@ The same document in the MongoDB shell might display as: :php:`MongoDB\\BSON\\Persistable ` may only be used for root and embedded BSON documents. It may not be used for BSON arrays. .. _php-type-map: + +Working with Enums +------------------ + +:php:`Backed enums ` can be used with BSON and will +serialize as their case value (i.e. integer or string). +:php:`Pure enums `, which have no backed cases, cannot be +directly serialized. This is similar to how enums are handled by +:php:`json_encode() `. + +Round-tripping a backed enum through BSON requires special handling. In the +following example, the `bsonUnserialize()` method in the class containing the +enum is responsible for converting the value back to an enum case: + +.. code-block:: php + + $this->_id, + 'username' => $this->username, + 'role' => $this->role, + ]; + } + + public function bsonUnserialize(array $data): void + { + $this->_id = $data['_id']; + $this->username = $data['username']; + $this->role = Role::from($data['role']); + } + } + +Enums are prohibited from implementing +:php:`MongoDB\\BSON\\Unserializable ` and +:php:`MongoDB\\BSON\\Persistable `, since enum cases +have no state and cannot be instantiated like ordinary objects. Pure and backed +enums can, however, implement +:php:`MongoDB\\BSON\\Serializable `, which can be +used to overcome the default behavior whereby backed enums are serialized as +their case value and pure enums cannot be serialized. From 3a681a3b2f2c0ebac227a3b86bb9057d0e6eb8f8 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 23 Nov 2022 12:45:35 +0800 Subject: [PATCH 229/321] Update composer.json and Evergreen matrices for 1.15.0 (#1006) * Bump PHPC versions in Evergreen matrix * Bump latest-stable server version to MongoDB 6.0 * Bump extension requirement and branch alias in composer.json The 1.14.x series is being skipped to restore version parity between the extension and library. --- .evergreen/config.yml | 20 +++++++------------- composer.json | 4 ++-- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 8171e22d8..3ddd859c3 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -680,9 +680,9 @@ axes: display_name: MongoDB Version values: - id: "latest-stable" - display_name: "MongoDB 5.0" + display_name: "MongoDB 6.0" variables: - VERSION: "5.0" + VERSION: "6.0" - id: "oldest-supported" display_name: "MongoDB 3.6" variables: @@ -691,22 +691,16 @@ axes: - id: driver-versions display_name: Driver Version values: - # TODO: Update to "1.15.0" once PHPC 1.15.0 is released - id: "oldest-supported" - # display_name: "1.15.0" - display_name: "PHPC 1.15-dev (master)" + display_name: "PHPC 1.15.0" variables: - # EXTENSION_VERSION: "1.15.0" - EXTENSION_BRANCH: "master" - # TODO: Update to "1.15.x"/"stable" once PHPC 1.15.0 is released + EXTENSION_VERSION: "1.15.0" - id: "latest-stable" - # display_name: "1.15.x" - display_name: "PHPC 1.15-dev (master)" + display_name: "PHPC (1.15.x)" variables: - # EXTENSION_VERSION: "stable" - EXTENSION_BRANCH: "master" + EXTENSION_VERSION: "stable" - id: "latest-dev" - display_name: "PHPC 1.15-dev (master)" + display_name: "PHPC (1.16-dev)" variables: EXTENSION_BRANCH: "master" diff --git a/composer.json b/composer.json index be1348928..8e55fabff 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.2 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.14.0", + "ext-mongodb": "^1.15.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.14.x-dev" + "dev-master": "1.15.x-dev" } }, "config": { From a1ef317c6993bf8e2b272a3e61783d14d93921ad Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 23 Nov 2022 12:49:22 +0800 Subject: [PATCH 230/321] Master is now 1.16-dev --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 8e55fabff..384bb0536 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "1.15.x-dev" + "dev-master": "1.16.x-dev" } }, "config": { From bf91db2558c491f474c986bc50383ff002ec9e01 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 23 Nov 2022 18:15:37 +0800 Subject: [PATCH 231/321] Revise release instructions (#1007) This is the PHPLIB counterpart to mongodb/mongo-php-driver@ab400ecdb9eb6713b305d8fbacf7eb0aa0c785b6 Add instructions for creating a maintenance branch after releasing a new minor version. * Use diff code blocks for more concise examples * Apply syntax highlighting to release notes examples Co-authored-by: Andreas Braun --- CONTRIBUTING.md | 108 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c43f249d6..5bbe3993d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -203,8 +203,18 @@ $ git commit -m "Master is now 1.10-dev" composer.json ## Releasing -The follow steps outline the release process for a maintenance branch (e.g. -releasing the `vX.Y` branch as X.Y.Z). +The following steps outline the release process for both new minor versions (e.g. +releasing the `master` branch as X.Y.0) and patch versions (e.g. releasing the +`vX.Y` branch as X.Y.Z). + +The command examples below assume that the canonical "mongodb" repository has +the remote name "mongodb". You may need to adjust these commands if you've given +the remote another name (e.g. "upstream"). The "origin" remote name was not used +as it likely refers to your personal fork. + +It helps to keep your own fork in sync with the "mongodb" repository (i.e. any +branches and tags on the main repository should also exist in your fork). This +is left as an exercise to the reader. ### Ensure PHP version compatibility @@ -234,50 +244,118 @@ changes in this maintenance branch. This is important because we will later merge the ensuing release commits up to master with `--strategy=ours`, which will ignore changes from the merged commits. -### Tag release +### Update composer.json and CI matrices + +This is especially important before releasing a new minor version. + +Ensure that the extension requirement and branch alias in `composer.json` are +correct for the library version being released. For example, the 1.15.0 release +of the library should depend on version `^1.15.0` of the extension and master +branch alias should be `1.15.x-dev`. + +If this is the first release of a minor version for the library, it is likely +following an extension release. In that case, the `driver-versions` matrix in +the Evergreen configuration should be updated: + +```diff + - id: "oldest-supported" +- display_name: "PHPC 1.15-dev" ++ display_name: "PHPC 1.15.0" + variables: +- EXTENSION_BRANCH: "master" ++ EXTENSION_VERSION: "1.15.0" + - id: "latest-stable" +- display_name: "PHPC 1.15-dev" ++ display_name: "PHPC 1.15.x" + variables: +- EXTENSION_BRANCH: "master" ++ EXTENSION_VERSION: "stable" + - id: "latest-dev" +- display_name: "PHPC 1.15-dev" ++ display_name: "PHPC 1.16-dev" + variables: + EXTENSION_BRANCH: "master" +``` + +Commit and push any changes: + +``` +$ git commit -m "Update composer.json and CI matrices for X.Y.Z" composer.json .evergreen/config.yml +$ git push mongodb +``` + +### Tag the release -The maintenance branch's HEAD will be the target for our release tag: +Create a tag for the release and push: ``` $ git tag -a -m "Release X.Y.Z" X.Y.Z +$ git push mongodb --tags ``` -### Push tags +### Branch management +#### After releasing a new minor version + +After a new minor version is released (i.e. `master` was tagged), a maintenance +branch should be created for future patch releases: + +``` +$ git checkout -b vX.Y +$ git push mongodb vX.Y +``` + +Update the master branch alias in `composer.json`: + +```diff + "extra": { + "branch-alias": { +- "dev-master": "1.15.x-dev" ++ "dev-master": "1.16.x-dev" + } + }, ``` -$ git push --tags + +Commit and push this change: + +``` +$ git commit -m "Master is now X.Y-dev" composer.json +$ git push mongodb ``` -### Merge the maintenance branch up to master +#### After releasing a patch version + +If this was a patch release, the maintenance branch must be merged up to master: ``` $ git checkout master +$ git pull mongodb master $ git merge vX.Y --strategy=ours -$ git push +$ git push mongodb ``` The `--strategy=ours` option ensures that all changes from the merged commits -will be ignored. +will be ignored. This is OK because we previously ensured that the `master` +branch was up-to-date with all code changes in this maintenance branch before +tagging. ### Publish release notes The following template should be used for creating GitHub release notes via [this form](https://github.com/mongodb/mongo-php-library/releases/new). -``` +```markdown The PHP team is happy to announce that version X.Y.Z of the MongoDB PHP library is now available. **Release Highlights** -A complete list of resolved issues in this release may be found at: -$JIRA_URL +A complete list of resolved issues in this release may be found in [JIRA]($JIRA_URL). **Documentation** -Documentation for this library may be found at: -https://mongodb.com/docs/php-library/current/ +Documentation for this library may be found in the [PHP Library Manual](https://mongodb.com/docs/php-library/current/). **Installation** @@ -295,7 +373,7 @@ release. You may obtain the list from If commits from community contributors were included in this release, append the following section: -``` +```markdown **Thanks** Thanks for our community contributors for this release: From 36223ef2d58aecc216dee2ae3132e4fa1c035831 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 29 Nov 2022 08:15:08 +0100 Subject: [PATCH 232/321] Ensure ExplainFunctionalTest does not optimise pipeline on MongoDB 6.3 (#1008) --- tests/Operation/ExplainFunctionalTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php index fe4f154e7..32f800f0e 100644 --- a/tests/Operation/ExplainFunctionalTest.php +++ b/tests/Operation/ExplainFunctionalTest.php @@ -365,7 +365,8 @@ public function testAggregate(): void $this->createFixtures(3); - $pipeline = [['$group' => ['_id' => null]]]; + // Use a $sort stage to ensure the aggregate does not get optimised to a query + $pipeline = [['$group' => ['_id' => null]], ['$sort' => ['_id' => 1]]]; $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), $pipeline); $explainOperation = new Explain($this->getDatabaseName(), $operation, ['verbosity' => Explain::VERBOSITY_QUERY, 'typeMap' => ['root' => 'array', 'document' => 'array']]); From 8e8364f74c5924e822396fd2c0a4e02659b70d01 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Tue, 29 Nov 2022 17:12:12 +0800 Subject: [PATCH 233/321] PHPLIB-866: CSFLE prose test for on-demand AWS credentials (#1009) --- .evergreen/config.yml | 19 +++++++++ .../ClientSideEncryptionSpecTest.php | 42 +++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 3ddd859c3..3c8d99764 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -598,6 +598,18 @@ tasks: SKIP_CRYPT_SHARED: "yes" TESTS: "csfle" + - name: "test-without_aws_credentials" + commands: + - func: "bootstrap mongo-orchestration" + vars: + TOPOLOGY: "replica_set" + - func: "start kms servers" + - func: "run tests" + vars: + client_side_encryption_aws_access_key_id: "" + client_side_encryption_aws_secret_access_key: "" + TESTS: "csfle" + # }}} @@ -863,3 +875,10 @@ buildvariants: display_name: "CSFLE skip_crypt_shared - ${mongodb-versions}" tasks: - name: "test-skip_crypt_shared" + +# Run CSFLE tests without AWS credentials (for "On-demand AWS Credentials" prose test) +- matrix_name: "test-csfle-without_aws_credentials" + matrix_spec: { "os": "debian11", "mongodb-versions": "6.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } + display_name: "CSFLE without_aws_credentials - ${mongodb-versions}" + tasks: + - name: "test-without_aws_credentials" diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index cba0323f1..b84b295c5 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -1642,6 +1642,48 @@ static function (self $test, Client $setupClient, ClientEncryption $clientEncryp ]; } + /** + * Prose test 15: On-demand AWS Credentials + * + * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#on-demand-aws-credentials + * @testWith [true] + * [false] + */ + public function testOnDemandAwsCredentials(bool $shouldSucceed): void + { + $hasCredentials = (getenv('AWS_ACCESS_KEY_ID') && getenv('AWS_SECRET_ACCESS_KEY')); + + if ($hasCredentials !== $shouldSucceed) { + Assert::markTestSkipped(sprintf('AWS credentials %s available', $hasCredentials ? 'are' : 'are not')); + } + + $keyVaultClient = static::createTestClient(); + + $clientEncryption = new ClientEncryption([ + 'keyVaultClient' => $keyVaultClient->getManager(), + 'keyVaultNamespace' => 'keyvault.datakeys', + 'kmsProviders' => ['aws' => (object) []], + ]); + + $dataKeyOpts = [ + 'masterKey' => [ + 'region' => 'us-east-1', + 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0', + ], + ]; + + if (! $shouldSucceed) { + $this->expectException(AuthenticationException::class); + } + + $dataKeyId = $clientEncryption->createDataKey('aws', $dataKeyOpts); + + if ($shouldSucceed) { + $this->assertInstanceOf(Binary::class, $dataKeyId); + $this->assertSame(Binary::TYPE_UUID, $dataKeyId->getType()); + } + } + /** * Prose test 16: RewrapManyDataKey * From 9b61868a609f8ff6dd2206356df3435fcc226b2e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Thu, 1 Dec 2022 20:54:34 +0800 Subject: [PATCH 234/321] PHPLIB-1043: Update observeSensitiveCommands tests for removed commands (#1003) Synced with mongodb/specifications@735a667672c758617821e3c5dda99c551e007375 --- .../command-monitoring/redacted-commands.json | 20 +++++++++++++++++++ .../valid-pass/observeSensitiveCommands.json | 15 ++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json b/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json index 0f85dc3e9..4302ba890 100644 --- a/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json +++ b/tests/UnifiedSpecTests/command-monitoring/redacted-commands.json @@ -162,6 +162,11 @@ }, { "description": "getnonce", + "runOnRequirements": [ + { + "maxServerVersion": "6.1.99" + } + ], "operations": [ { "name": "runCommand", @@ -293,6 +298,11 @@ }, { "description": "copydbgetnonce", + "runOnRequirements": [ + { + "maxServerVersion": "3.6.99" + } + ], "operations": [ { "name": "runCommand", @@ -328,6 +338,11 @@ }, { "description": "copydbsaslstart", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], "operations": [ { "name": "runCommand", @@ -363,6 +378,11 @@ }, { "description": "copydb", + "runOnRequirements": [ + { + "maxServerVersion": "4.0.99" + } + ], "operations": [ { "name": "runCommand", diff --git a/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json b/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json index 411ca19c5..d3ae5665b 100644 --- a/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json +++ b/tests/UnifiedSpecTests/valid-pass/observeSensitiveCommands.json @@ -61,6 +61,11 @@ "tests": [ { "description": "getnonce is observed with observeSensitiveCommands=true", + "runOnRequirements": [ + { + "maxServerVersion": "6.1.99" + } + ], "operations": [ { "name": "runCommand", @@ -106,6 +111,11 @@ }, { "description": "getnonce is not observed with observeSensitiveCommands=false", + "runOnRequirements": [ + { + "maxServerVersion": "6.1.99" + } + ], "operations": [ { "name": "runCommand", @@ -127,6 +137,11 @@ }, { "description": "getnonce is not observed by default", + "runOnRequirements": [ + { + "maxServerVersion": "6.1.99" + } + ], "operations": [ { "name": "runCommand", From 4c090a88821db2665bf77a0742ae81efec121380 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 6 Dec 2022 09:58:44 +0100 Subject: [PATCH 235/321] PHPLIB-909: Add more error response tests (#1012) * Require latest driver version * PHPLIB-909: Assert error responses for WriteExceptions --- .evergreen/config.yml | 10 ++++++---- composer.json | 2 +- tests/UnifiedSpecTests/ExpectedError.php | 15 +++++++++++++-- tests/UnifiedSpecTests/UnifiedSpecTest.php | 5 ----- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 3c8d99764..22d17b9b0 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -704,13 +704,15 @@ axes: display_name: Driver Version values: - id: "oldest-supported" - display_name: "PHPC 1.15.0" + display_name: "PHPC 1.16.0" variables: - EXTENSION_VERSION: "1.15.0" + EXTENSION_BRANCH: "master" +# EXTENSION_VERSION: "1.16.0" - id: "latest-stable" - display_name: "PHPC (1.15.x)" + display_name: "PHPC (1.16.x)" variables: - EXTENSION_VERSION: "stable" + EXTENSION_BRANCH: "master" +# EXTENSION_VERSION: "stable" - id: "latest-dev" display_name: "PHPC (1.16-dev)" variables: diff --git a/composer.json b/composer.json index 384bb0536..f26bb053b 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": "^7.2 || ^8.0", "ext-hash": "*", "ext-json": "*", - "ext-mongodb": "^1.15.0", + "ext-mongodb": "^1.16.0", "jean85/pretty-package-versions": "^1.2 || ^2.0.1", "symfony/polyfill-php80": "^1.19" }, diff --git a/tests/UnifiedSpecTests/ExpectedError.php b/tests/UnifiedSpecTests/ExpectedError.php index b99a9f2ac..a57ef341a 100644 --- a/tests/UnifiedSpecTests/ExpectedError.php +++ b/tests/UnifiedSpecTests/ExpectedError.php @@ -7,6 +7,7 @@ use MongoDB\Driver\Exception\ExecutionTimeoutException; use MongoDB\Driver\Exception\RuntimeException; use MongoDB\Driver\Exception\ServerException; +use MongoDB\Driver\Exception\WriteException; use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches; use PHPUnit\Framework\Assert; use stdClass; @@ -15,6 +16,7 @@ use function get_class; use function PHPUnit\Framework\assertArrayHasKey; use function PHPUnit\Framework\assertContainsOnly; +use function PHPUnit\Framework\assertCount; use function PHPUnit\Framework\assertFalse; use function PHPUnit\Framework\assertInstanceOf; use function PHPUnit\Framework\assertIsArray; @@ -30,6 +32,8 @@ use function PHPUnit\Framework\assertStringContainsStringIgnoringCase; use function PHPUnit\Framework\assertThat; use function PHPUnit\Framework\assertTrue; +use function PHPUnit\Framework\isInstanceOf; +use function PHPUnit\Framework\logicalOr; use function property_exists; use function sprintf; @@ -166,8 +170,15 @@ public function assert(?Throwable $e = null): void } if (isset($this->matchesResultDocument)) { - assertInstanceOf(CommandException::class, $e); - assertThat($e->getResultDocument(), $this->matchesResultDocument, 'CommandException result document matches'); + assertThat($e, logicalOr(isInstanceOf(CommandException::class), isInstanceOf(WriteException::class))); + + if ($e instanceof CommandException) { + assertThat($e->getResultDocument(), $this->matchesResultDocument, 'CommandException result document matches'); + } elseif ($e instanceof WriteException) { + $writeErrors = $e->getWriteResult()->getErrorReplies(); + assertCount(1, $writeErrors); + assertThat($writeErrors[0], $this->matchesResultDocument, 'WriteException result document matches'); + } } if (! empty($this->excludedLabels) || ! empty($this->includedLabels)) { diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index cd5a140da..9a4fea23f 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -65,11 +65,6 @@ class UnifiedSpecTest extends FunctionalTestCase 'valid-pass/createEntities-operation: createEntities operation' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/entity-cursor-iterateOnce: iterateOnce' => 'CSOT is not yet implemented (PHPC-1760)', 'valid-pass/matches-lte-operator: special lte matching operator' => 'CSOT is not yet implemented (PHPC-1760)', - // BulkWriteException cannot access server response - 'crud/bulkWrite-errorResponse: bulkWrite operations support errorResponse assertions' => 'BulkWriteException cannot access server response', - 'crud/deleteOne-errorResponse: delete operations support errorResponse assertions' => 'BulkWriteException cannot access server response', - 'crud/insertOne-errorResponse: insert operations support errorResponse assertions' => 'BulkWriteException cannot access server response', - 'crud/updateOne-errorResponse: update operations support errorResponse assertions' => 'BulkWriteException cannot access server response', ]; /** @var UnifiedTestRunner */ From c1d462af62d6070e2588871d852567a27b3b22f9 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 12 Dec 2022 03:31:23 -0500 Subject: [PATCH 236/321] Remove redundant code in CSFLE legacy spec test runner (#1013) This was missed in a495bf5369f08048b5467803d9abdec35edac2bb for PHPLIB-884 --- tests/SpecTests/ClientSideEncryptionSpecTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index b84b295c5..32361f755 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -131,11 +131,6 @@ public function testClientSideEncryption(stdClass $test, ?array $runOn, array $d $databaseName = $databaseName ?? $this->getDatabaseName(); $collectionName = $collectionName ?? $this->getCollectionName(); - // TODO: Remove this once SERVER-66901 is implemented (see: PHPLIB-884) - if (isset($test->clientOptions->autoEncryptOpts->encryptedFieldsMap)) { - $test->clientOptions->autoEncryptOpts->encryptedFieldsMap = $test->clientOptions->autoEncryptOpts->encryptedFieldsMap; - } - try { $context = Context::fromClientSideEncryption($test, $databaseName, $collectionName); } catch (SkippedTestError $e) { From 25966fffaa7bb83e2435d3d4a04b4afbae3436b2 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 14 Dec 2022 08:46:21 +0100 Subject: [PATCH 237/321] PHPLIB-1046: Fix snooty errors in documentation (#1010) * Remove literal code blocks * Fix minor errors in documentation * Add missing code-block directives * Fix more docs errors * Fix wrong backticks style --- ...tabase-method-createCollection-option.yaml | 8 ++- docs/reference/class/MongoDBCollection.txt | 23 ++++--- docs/reference/class/MongoDBDatabase.txt | 2 +- docs/reference/class/MongoDBGridFSBucket.txt | 2 +- .../MongoDBChangeStream-getCursorId.txt | 4 +- .../method/MongoDBClient-dropDatabase.txt | 4 +- .../method/MongoDBClient-getReadConcern.txt | 4 +- .../MongoDBClient-getReadPreference.txt | 4 +- .../method/MongoDBClient-getTypeMap.txt | 4 +- .../method/MongoDBClient-getWriteConcern.txt | 4 +- .../MongoDBClient-listDatabaseNames.txt | 4 +- .../method/MongoDBClient-listDatabases.txt | 4 +- .../method/MongoDBClient-startSession.txt | 4 +- docs/reference/method/MongoDBClient__get.txt | 4 +- .../method/MongoDBCollection-createIndex.txt | 8 ++- .../MongoDBCollection-createIndexes.txt | 10 ++- .../method/MongoDBCollection-deleteMany.txt | 4 +- .../method/MongoDBCollection-deleteOne.txt | 4 +- .../method/MongoDBCollection-distinct.txt | 8 ++- .../method/MongoDBCollection-drop.txt | 4 +- .../method/MongoDBCollection-dropIndex.txt | 4 +- .../method/MongoDBCollection-dropIndexes.txt | 4 +- .../method/MongoDBCollection-explain.txt | 28 +++++---- .../method/MongoDBCollection-find.txt | 4 +- .../method/MongoDBCollection-findOne.txt | 4 +- .../MongoDBCollection-findOneAndDelete.txt | 4 +- .../MongoDBCollection-findOneAndReplace.txt | 4 +- .../MongoDBCollection-findOneAndUpdate.txt | 4 +- .../MongoDBCollection-getCollectionName.txt | 4 +- .../MongoDBCollection-getDatabaseName.txt | 4 +- .../method/MongoDBCollection-getNamespace.txt | 4 +- .../MongoDBCollection-getReadConcern.txt | 4 +- .../MongoDBCollection-getReadPreference.txt | 4 +- .../method/MongoDBCollection-getTypeMap.txt | 4 +- .../MongoDBCollection-getWriteConcern.txt | 4 +- .../method/MongoDBCollection-insertMany.txt | 4 +- .../method/MongoDBCollection-insertOne.txt | 4 +- .../method/MongoDBCollection-listIndexes.txt | 4 +- .../method/MongoDBCollection-mapReduce.txt | 4 +- .../method/MongoDBCollection-rename.txt | 4 +- .../method/MongoDBCollection-replaceOne.txt | 4 +- .../method/MongoDBCollection-updateMany.txt | 4 +- .../method/MongoDBCollection-updateOne.txt | 4 +- .../method/MongoDBDatabase-command.txt | 8 ++- .../MongoDBDatabase-createCollection.txt | 4 +- .../reference/method/MongoDBDatabase-drop.txt | 4 +- .../method/MongoDBDatabase-dropCollection.txt | 4 +- .../MongoDBDatabase-getDatabaseName.txt | 4 +- .../method/MongoDBDatabase-getReadConcern.txt | 4 +- .../MongoDBDatabase-getReadPreference.txt | 4 +- .../method/MongoDBDatabase-getTypeMap.txt | 4 +- .../MongoDBDatabase-getWriteConcern.txt | 4 +- .../MongoDBDatabase-listCollectionNames.txt | 8 ++- .../MongoDBDatabase-listCollections.txt | 8 ++- .../MongoDBDatabase-modifyCollection.txt | 4 +- .../MongoDBDatabase-renameCollection.txt | 4 +- .../reference/method/MongoDBDatabase__get.txt | 4 +- .../MongoDBGridFSBucket-downloadToStream.txt | 4 +- ...oDBGridFSBucket-downloadToStreamByName.txt | 4 +- .../method/MongoDBGridFSBucket-find.txt | 4 +- .../method/MongoDBGridFSBucket-findOne.txt | 4 +- .../MongoDBGridFSBucket-getBucketName.txt | 4 +- .../MongoDBGridFSBucket-getChunkSizeBytes.txt | 4 +- ...ongoDBGridFSBucket-getChunksCollection.txt | 4 +- .../MongoDBGridFSBucket-getDatabaseName.txt | 4 +- ...BGridFSBucket-getFileDocumentForStream.txt | 4 +- ...MongoDBGridFSBucket-getFileIdForStream.txt | 4 +- ...MongoDBGridFSBucket-getFilesCollection.txt | 4 +- .../MongoDBGridFSBucket-getReadConcern.txt | 4 +- .../MongoDBGridFSBucket-getReadPreference.txt | 4 +- .../method/MongoDBGridFSBucket-getTypeMap.txt | 4 +- .../MongoDBGridFSBucket-getWriteConcern.txt | 4 +- ...MongoDBGridFSBucket-openDownloadStream.txt | 4 +- ...BGridFSBucket-openDownloadStreamByName.txt | 4 +- .../MongoDBGridFSBucket-openUploadStream.txt | 4 +- .../method/MongoDBGridFSBucket-rename.txt | 4 +- .../MongoDBGridFSBucket-uploadFromStream.txt | 4 +- .../method/MongoDBGridFSBucket__construct.txt | 4 +- .../MongoDBMapReduceResult-getCounts.txt | 4 +- ...goDBMapReduceResult-getExecutionTimeMS.txt | 4 +- .../MongoDBMapReduceResult-getIterator.txt | 6 +- .../MongoDBMapReduceResult-getTiming.txt | 4 +- ...ongoDBModelCollectionInfo-getCappedMax.txt | 4 +- ...ngoDBModelCollectionInfo-getCappedSize.txt | 4 +- .../MongoDBModelCollectionInfo-getIdIndex.txt | 4 +- .../MongoDBModelCollectionInfo-getInfo.txt | 4 +- .../MongoDBModelCollectionInfo-getName.txt | 4 +- .../MongoDBModelCollectionInfo-getOptions.txt | 4 +- .../MongoDBModelCollectionInfo-getType.txt | 4 +- .../MongoDBModelCollectionInfo-isCapped.txt | 4 +- .../MongoDBModelDatabaseInfo-getName.txt | 4 +- ...MongoDBModelDatabaseInfo-getSizeOnDisk.txt | 4 +- .../MongoDBModelDatabaseInfo-isEmpty.txt | 4 +- .../method/MongoDBModelIndexInfo-getKey.txt | 4 +- .../method/MongoDBModelIndexInfo-getName.txt | 4 +- .../MongoDBModelIndexInfo-getNamespace.txt | 4 +- .../MongoDBModelIndexInfo-getVersion.txt | 4 +- .../MongoDBModelIndexInfo-is2dSphere.txt | 4 +- .../MongoDBModelIndexInfo-isGeoHaystack.txt | 4 +- .../method/MongoDBModelIndexInfo-isSparse.txt | 4 +- .../method/MongoDBModelIndexInfo-isText.txt | 4 +- .../method/MongoDBModelIndexInfo-isTtl.txt | 4 +- .../method/MongoDBModelIndexInfo-isUnique.txt | 4 +- docs/tutorial/collation.txt | 6 +- docs/tutorial/commands.txt | 16 +++-- docs/tutorial/crud.txt | 62 ++++++++++++++----- docs/tutorial/custom-types.txt | 4 +- docs/tutorial/decimal128.txt | 12 +++- docs/tutorial/example-data.txt | 6 +- docs/tutorial/gridfs.txt | 16 ++--- docs/tutorial/indexes.txt | 14 +++-- docs/tutorial/modeling-bson-data.txt | 2 +- docs/upgrade.txt | 8 ++- 113 files changed, 446 insertions(+), 183 deletions(-) diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml index f95b406c2..348be4b09 100644 --- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml +++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml @@ -143,8 +143,10 @@ description: | collection. The ``indexOptionDefaults`` option accepts a ``storageEngine`` document, - which should take the following form:: + which should take the following form: + .. code-block:: none + { : } Storage engine configurations specified when creating indexes are validated @@ -212,8 +214,10 @@ description: | Allows users to specify configuration to the storage engine on a per-collection basis when creating a collection. The value of the - ``storageEngine`` option should take the following form:: + ``storageEngine`` option should take the following form: + .. code-block:: none + { : } Storage engine configurations specified when creating collections are diff --git a/docs/reference/class/MongoDBCollection.txt b/docs/reference/class/MongoDBCollection.txt index 57625ed02..9c9aa3134 100644 --- a/docs/reference/class/MongoDBCollection.txt +++ b/docs/reference/class/MongoDBCollection.txt @@ -23,7 +23,7 @@ Definition select a collection from the library's :phpclass:`MongoDB\\Client` or :phpclass:`MongoDB\\Database` classes. A collection may also be cloned from an existing :phpclass:`MongoDB\\Collection` object via the - :phpmethod:`withOptions() ` method. + :phpmethod:`withOptions() ` method. :phpclass:`MongoDB\\Collection` supports the :php:`readConcern `, :php:`readPreference @@ -41,17 +41,16 @@ Definition Type Map Limitations -------------------- - The :manual:`aggregate ` (when not using a - cursor), :manual:`distinct `, and - :manual:`findAndModify ` helpers do not - support a ``typeMap`` option due to a driver limitation. The - :phpmethod:`aggregate() `, - :phpmethod:`distinct() `, - :phpmethod:`findOneAndReplace() `, - :phpmethod:`findOneAndUpdate() `, and - :phpmethod:`findOneAndDelete() ` - methods return BSON documents as `stdClass` objects and BSON arrays as - arrays. +The :manual:`aggregate ` (when not using a +cursor), :manual:`distinct `, and +:manual:`findAndModify ` helpers do not +support a ``typeMap`` option due to a driver limitation. The +:phpmethod:`aggregate() `, +:phpmethod:`distinct() `, +:phpmethod:`findOneAndReplace() `, +:phpmethod:`findOneAndUpdate() `, and +:phpmethod:`findOneAndDelete() ` +methods return BSON documents as ``stdClass`` objects and BSON arrays as arrays. Methods ------- diff --git a/docs/reference/class/MongoDBDatabase.txt b/docs/reference/class/MongoDBDatabase.txt index 7e7cb73d9..a4a7dd99d 100644 --- a/docs/reference/class/MongoDBDatabase.txt +++ b/docs/reference/class/MongoDBDatabase.txt @@ -22,7 +22,7 @@ Definition :php:`MongoDB\\Driver\\Manager ` class or select a database from the library's :phpclass:`MongoDB\\Client` class. A database may also be cloned from an existing :phpclass:`MongoDB\\Database` - object via the :phpmethod:`withOptions() ` + object via the :phpmethod:`withOptions() ` method. :phpclass:`MongoDB\\Database` supports the :php:`readConcern diff --git a/docs/reference/class/MongoDBGridFSBucket.txt b/docs/reference/class/MongoDBGridFSBucket.txt index cea877f43..0fdeb5cb8 100644 --- a/docs/reference/class/MongoDBGridFSBucket.txt +++ b/docs/reference/class/MongoDBGridFSBucket.txt @@ -25,7 +25,7 @@ Definition You can construct a GridFS bucket using the driver's :php:`Manager ` class, or select a bucket from the library's :phpclass:`MongoDB\\Database` class via the - :phpmethod:`selectGridFSBucket() ` + :phpmethod:`selectGridFSBucket() ` method. Methods diff --git a/docs/reference/method/MongoDBChangeStream-getCursorId.txt b/docs/reference/method/MongoDBChangeStream-getCursorId.txt index 1938d3c00..e7004f441 100644 --- a/docs/reference/method/MongoDBChangeStream-getCursorId.txt +++ b/docs/reference/method/MongoDBChangeStream-getCursorId.txt @@ -43,7 +43,9 @@ This example reports the cursor ID for a change stream. var_dump($changeStream->getCursorId()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\CursorId)#5 (1) { ["id"]=> diff --git a/docs/reference/method/MongoDBClient-dropDatabase.txt b/docs/reference/method/MongoDBClient-dropDatabase.txt index 4369d07f2..3e963ee5c 100644 --- a/docs/reference/method/MongoDBClient-dropDatabase.txt +++ b/docs/reference/method/MongoDBClient-dropDatabase.txt @@ -58,7 +58,9 @@ The following example drops the ``test`` database: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#8 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBClient-getReadConcern.txt b/docs/reference/method/MongoDBClient-getReadConcern.txt index b7c4c60bc..64f2b3d4a 100644 --- a/docs/reference/method/MongoDBClient-getReadConcern.txt +++ b/docs/reference/method/MongoDBClient-getReadConcern.txt @@ -41,7 +41,9 @@ Example var_dump($client->getReadConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadConcern)#5 (1) { ["level"]=> diff --git a/docs/reference/method/MongoDBClient-getReadPreference.txt b/docs/reference/method/MongoDBClient-getReadPreference.txt index 96d8eec59..cd00f206c 100644 --- a/docs/reference/method/MongoDBClient-getReadPreference.txt +++ b/docs/reference/method/MongoDBClient-getReadPreference.txt @@ -42,7 +42,9 @@ Example var_dump($client->getReadPreference()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadPreference)#5 (1) { ["mode"]=> diff --git a/docs/reference/method/MongoDBClient-getTypeMap.txt b/docs/reference/method/MongoDBClient-getTypeMap.txt index 04697f335..138444f06 100644 --- a/docs/reference/method/MongoDBClient-getTypeMap.txt +++ b/docs/reference/method/MongoDBClient-getTypeMap.txt @@ -45,7 +45,9 @@ Example var_dump($client->getTypeMap()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(3) { ["root"]=> diff --git a/docs/reference/method/MongoDBClient-getWriteConcern.txt b/docs/reference/method/MongoDBClient-getWriteConcern.txt index b779aae96..7a3e561c6 100644 --- a/docs/reference/method/MongoDBClient-getWriteConcern.txt +++ b/docs/reference/method/MongoDBClient-getWriteConcern.txt @@ -42,7 +42,9 @@ Example var_dump($client->getWriteConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\WriteConcern)#4 (1) { ["j"]=> diff --git a/docs/reference/method/MongoDBClient-listDatabaseNames.txt b/docs/reference/method/MongoDBClient-listDatabaseNames.txt index 5047b88d7..bf4fb48fe 100644 --- a/docs/reference/method/MongoDBClient-listDatabaseNames.txt +++ b/docs/reference/method/MongoDBClient-listDatabaseNames.txt @@ -59,7 +59,9 @@ The following example lists all databases on the server: var_dump($databaseName); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(5) "local" string(4) "test" diff --git a/docs/reference/method/MongoDBClient-listDatabases.txt b/docs/reference/method/MongoDBClient-listDatabases.txt index 7f27cee8e..822f98d7c 100644 --- a/docs/reference/method/MongoDBClient-listDatabases.txt +++ b/docs/reference/method/MongoDBClient-listDatabases.txt @@ -58,7 +58,9 @@ The following example lists all databases on the server: var_dump($databaseInfo); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\DatabaseInfo)#4 (3) { ["name"]=> diff --git a/docs/reference/method/MongoDBClient-startSession.txt b/docs/reference/method/MongoDBClient-startSession.txt index c3fcce89a..07a9b2b20 100644 --- a/docs/reference/method/MongoDBClient-startSession.txt +++ b/docs/reference/method/MongoDBClient-startSession.txt @@ -53,7 +53,9 @@ The following example starts a new session: var_dump($session); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\Session)#2043 (4) { ["logicalSessionId"]=> diff --git a/docs/reference/method/MongoDBClient__get.txt b/docs/reference/method/MongoDBClient__get.txt index c0af748c3..5e4097b2d 100644 --- a/docs/reference/method/MongoDBClient__get.txt +++ b/docs/reference/method/MongoDBClient__get.txt @@ -17,7 +17,7 @@ Definition Selects a database on the server. This :php:`magic method ` is an alias for the :phpmethod:`selectDatabase() - ` method. + ` method. .. code-block:: php @@ -37,7 +37,7 @@ Behavior The selected database inherits options such as read preference and type mapping from the :phpclass:`Client ` object. If you wish to override -any options, use the :phpmethod:`MongoDB\\Client::selectDatabase` method. +any options, use the :phpmethod:`MongoDB\\Client::selectDatabase()` method. .. note:: diff --git a/docs/reference/method/MongoDBCollection-createIndex.txt b/docs/reference/method/MongoDBCollection-createIndex.txt index bdae57123..344242e0f 100644 --- a/docs/reference/method/MongoDBCollection-createIndex.txt +++ b/docs/reference/method/MongoDBCollection-createIndex.txt @@ -66,7 +66,9 @@ the ``test`` database. var_dump($indexName); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(19) "borough_1_cuisine_1" @@ -95,7 +97,9 @@ exists. var_dump($indexName); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(9) "borough_1" diff --git a/docs/reference/method/MongoDBCollection-createIndexes.txt b/docs/reference/method/MongoDBCollection-createIndexes.txt index 05a3c0be3..76705e9ba 100644 --- a/docs/reference/method/MongoDBCollection-createIndexes.txt +++ b/docs/reference/method/MongoDBCollection-createIndexes.txt @@ -13,7 +13,7 @@ MongoDB\\Collection::createIndexes() Definition ---------- -.. phpmethod:: MongoDB\\Collection::createIndexes($indexes) +.. phpmethod:: MongoDB\\Collection::createIndexes() Create one or more indexes for the collection. @@ -53,7 +53,9 @@ fields that correspond to index options accepted by :phpmethod:`createIndex() For example, the following ``$indexes`` parameter creates two indexes. The first is an ascending unique index on the ``username`` field and the second is a -2dsphere index on the ``loc`` field with a custom name:: +2dsphere index on the ``loc`` field with a custom name: + +.. code-block:: none [ [ 'key' => [ 'username' => 1 ], 'unique' => true ], @@ -81,7 +83,9 @@ custom name. var_dump($indexNames); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(2) { [0]=> diff --git a/docs/reference/method/MongoDBCollection-deleteMany.txt b/docs/reference/method/MongoDBCollection-deleteMany.txt index df1a1ac81..a9fc24c11 100644 --- a/docs/reference/method/MongoDBCollection-deleteMany.txt +++ b/docs/reference/method/MongoDBCollection-deleteMany.txt @@ -68,7 +68,9 @@ that have ``"ny"`` as the value for the ``state`` field: printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Deleted 2 document(s) diff --git a/docs/reference/method/MongoDBCollection-deleteOne.txt b/docs/reference/method/MongoDBCollection-deleteOne.txt index 0c31bfb5f..dcfb26285 100644 --- a/docs/reference/method/MongoDBCollection-deleteOne.txt +++ b/docs/reference/method/MongoDBCollection-deleteOne.txt @@ -70,7 +70,9 @@ has ``"ny"`` as the value for the ``state`` field: printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Deleted 1 document(s) diff --git a/docs/reference/method/MongoDBCollection-distinct.txt b/docs/reference/method/MongoDBCollection-distinct.txt index bb0c94ca5..7d5f7ee6d 100644 --- a/docs/reference/method/MongoDBCollection-distinct.txt +++ b/docs/reference/method/MongoDBCollection-distinct.txt @@ -66,7 +66,9 @@ in the ``restaurants`` collection in the ``test`` database. var_dump($distinct); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(6) { [0]=> @@ -100,7 +102,9 @@ the ``borough`` is ``Queens``: var_dump($distinct); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(75) { [0]=> diff --git a/docs/reference/method/MongoDBCollection-drop.txt b/docs/reference/method/MongoDBCollection-drop.txt index c1762871b..a2cd9410b 100644 --- a/docs/reference/method/MongoDBCollection-drop.txt +++ b/docs/reference/method/MongoDBCollection-drop.txt @@ -59,7 +59,9 @@ database: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#9 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-dropIndex.txt b/docs/reference/method/MongoDBCollection-dropIndex.txt index 880349bdf..cefcf6763 100644 --- a/docs/reference/method/MongoDBCollection-dropIndex.txt +++ b/docs/reference/method/MongoDBCollection-dropIndex.txt @@ -59,7 +59,9 @@ collection in the ``test`` database: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#9 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-dropIndexes.txt b/docs/reference/method/MongoDBCollection-dropIndexes.txt index 8cdf9e43a..ee48d493c 100644 --- a/docs/reference/method/MongoDBCollection-dropIndexes.txt +++ b/docs/reference/method/MongoDBCollection-dropIndexes.txt @@ -60,7 +60,9 @@ The following drops all indexes from the ``restaurants`` collection in the var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#9 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-explain.txt b/docs/reference/method/MongoDBCollection-explain.txt index 5ae73c911..68a8965aa 100644 --- a/docs/reference/method/MongoDBCollection-explain.txt +++ b/docs/reference/method/MongoDBCollection-explain.txt @@ -50,18 +50,18 @@ Explainable Commands Explainable commands include, but are not limited to: - - :phpclass:`MongoDB\\Operation\\Aggregate` - - :phpclass:`MongoDB\\Operation\\Count` - - :phpclass:`MongoDB\\Operation\\DeleteMany` - - :phpclass:`MongoDB\\Operation\\DeleteOne` - - :phpclass:`MongoDB\\Operation\\Distinct` - - :phpclass:`MongoDB\\Operation\\Find` - - :phpclass:`MongoDB\\Operation\\FindOne` - - :phpclass:`MongoDB\\Operation\\FindOneAndDelete` - - :phpclass:`MongoDB\\Operation\\FindOneAndReplace` - - :phpclass:`MongoDB\\Operation\\FindOneAndUpdate` - - :phpclass:`MongoDB\\Operation\\UpdateMany` - - :phpclass:`MongoDB\\Operation\\UpdateOne` +- ``MongoDB\Operation\Aggregate`` +- ``MongoDB\Operation\Count`` +- ``MongoDB\Operation\DeleteMany`` +- ``MongoDB\Operation\DeleteOne`` +- ``MongoDB\Operation\Distinct`` +- ``MongoDB\Operation\Find`` +- ``MongoDB\Operation\FindOne`` +- ``MongoDB\Operation\FindOneAndDelete`` +- ``MongoDB\Operation\FindOneAndReplace`` +- ``MongoDB\Operation\FindOneAndUpdate`` +- ``MongoDB\Operation\UpdateMany`` +- ``MongoDB\Operation\UpdateOne`` Examples -------- @@ -84,7 +84,9 @@ This example explains a count command. var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#29 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-find.txt b/docs/reference/method/MongoDBCollection-find.txt index 34eed99ad..2a5e2afb7 100644 --- a/docs/reference/method/MongoDBCollection-find.txt +++ b/docs/reference/method/MongoDBCollection-find.txt @@ -77,7 +77,9 @@ returned. It also limits the results to 5 documents. var_dump($restaurant); }; -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#10 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-findOne.txt b/docs/reference/method/MongoDBCollection-findOne.txt index 0bf95f648..3ebd2b531 100644 --- a/docs/reference/method/MongoDBCollection-findOne.txt +++ b/docs/reference/method/MongoDBCollection-findOne.txt @@ -98,7 +98,9 @@ returned. var_dump($restaurant); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#10 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-findOneAndDelete.txt b/docs/reference/method/MongoDBCollection-findOneAndDelete.txt index 1253bad40..bdf20da9c 100644 --- a/docs/reference/method/MongoDBCollection-findOneAndDelete.txt +++ b/docs/reference/method/MongoDBCollection-findOneAndDelete.txt @@ -73,7 +73,9 @@ The following example finds and deletes the document with ``restaurant_id`` of var_dump($deletedRestaurant); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#17 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-findOneAndReplace.txt b/docs/reference/method/MongoDBCollection-findOneAndReplace.txt index 6a96a30b0..4b29d8ad5 100644 --- a/docs/reference/method/MongoDBCollection-findOneAndReplace.txt +++ b/docs/reference/method/MongoDBCollection-findOneAndReplace.txt @@ -115,7 +115,9 @@ The following operation replaces the document with ``restaurant_id`` of var_dump($replacedRestaurant); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#18 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt b/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt index 377d255ed..65ea436dd 100644 --- a/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt +++ b/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt @@ -74,7 +74,9 @@ setting its building number to ``"761"``: var_dump($updatedRestaurant); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#20 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-getCollectionName.txt b/docs/reference/method/MongoDBCollection-getCollectionName.txt index 86fe3e5ec..70be8a8a1 100644 --- a/docs/reference/method/MongoDBCollection-getCollectionName.txt +++ b/docs/reference/method/MongoDBCollection-getCollectionName.txt @@ -40,7 +40,9 @@ The following returns the collection name for the ``zips`` collection in the echo $collection->getCollectionName(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none zips diff --git a/docs/reference/method/MongoDBCollection-getDatabaseName.txt b/docs/reference/method/MongoDBCollection-getDatabaseName.txt index 93500c809..f83632bac 100644 --- a/docs/reference/method/MongoDBCollection-getDatabaseName.txt +++ b/docs/reference/method/MongoDBCollection-getDatabaseName.txt @@ -40,7 +40,9 @@ The following returns the database name for the ``zips`` collection in the echo $collection->getDatabaseName(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none test diff --git a/docs/reference/method/MongoDBCollection-getNamespace.txt b/docs/reference/method/MongoDBCollection-getNamespace.txt index 74f1b022e..78e2484be 100644 --- a/docs/reference/method/MongoDBCollection-getNamespace.txt +++ b/docs/reference/method/MongoDBCollection-getNamespace.txt @@ -41,7 +41,9 @@ database. echo $collection->getNamespace(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none test.zips diff --git a/docs/reference/method/MongoDBCollection-getReadConcern.txt b/docs/reference/method/MongoDBCollection-getReadConcern.txt index ff1cfeb04..2a40efedf 100644 --- a/docs/reference/method/MongoDBCollection-getReadConcern.txt +++ b/docs/reference/method/MongoDBCollection-getReadConcern.txt @@ -41,7 +41,9 @@ Example var_dump($collection->getReadConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadConcern)#5 (1) { ["level"]=> diff --git a/docs/reference/method/MongoDBCollection-getReadPreference.txt b/docs/reference/method/MongoDBCollection-getReadPreference.txt index 4eac30d3a..622701e55 100644 --- a/docs/reference/method/MongoDBCollection-getReadPreference.txt +++ b/docs/reference/method/MongoDBCollection-getReadPreference.txt @@ -42,7 +42,9 @@ Example var_dump($collection->getReadPreference()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadPreference)#5 (1) { ["mode"]=> diff --git a/docs/reference/method/MongoDBCollection-getTypeMap.txt b/docs/reference/method/MongoDBCollection-getTypeMap.txt index 11e56426a..50cd91dad 100644 --- a/docs/reference/method/MongoDBCollection-getTypeMap.txt +++ b/docs/reference/method/MongoDBCollection-getTypeMap.txt @@ -45,7 +45,9 @@ Example var_dump($collection->getTypeMap()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(3) { ["root"]=> diff --git a/docs/reference/method/MongoDBCollection-getWriteConcern.txt b/docs/reference/method/MongoDBCollection-getWriteConcern.txt index 4fa26ee1f..a7ad354db 100644 --- a/docs/reference/method/MongoDBCollection-getWriteConcern.txt +++ b/docs/reference/method/MongoDBCollection-getWriteConcern.txt @@ -42,7 +42,9 @@ Example var_dump($collection->getWriteConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\WriteConcern)#5 (2) { ["w"]=> diff --git a/docs/reference/method/MongoDBCollection-insertMany.txt b/docs/reference/method/MongoDBCollection-insertMany.txt index 8b7eb53b0..62b0858e6 100644 --- a/docs/reference/method/MongoDBCollection-insertMany.txt +++ b/docs/reference/method/MongoDBCollection-insertMany.txt @@ -79,7 +79,9 @@ in the ``test`` database: var_dump($insertManyResult->getInsertedIds()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Inserted 2 document(s) array(2) { diff --git a/docs/reference/method/MongoDBCollection-insertOne.txt b/docs/reference/method/MongoDBCollection-insertOne.txt index 0d25f6d51..aa4380500 100644 --- a/docs/reference/method/MongoDBCollection-insertOne.txt +++ b/docs/reference/method/MongoDBCollection-insertOne.txt @@ -71,7 +71,9 @@ The following operation inserts a document into the ``users`` collection in the var_dump($insertOneResult->getInsertedId()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Inserted 1 document(s) object(MongoDB\BSON\ObjectId)#11 (1) { diff --git a/docs/reference/method/MongoDBCollection-listIndexes.txt b/docs/reference/method/MongoDBCollection-listIndexes.txt index e39a9bbba..2508b2828 100644 --- a/docs/reference/method/MongoDBCollection-listIndexes.txt +++ b/docs/reference/method/MongoDBCollection-listIndexes.txt @@ -57,7 +57,9 @@ collection in the ``test`` database: var_dump($index); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\IndexInfo)#8 (4) { ["v"]=> diff --git a/docs/reference/method/MongoDBCollection-mapReduce.txt b/docs/reference/method/MongoDBCollection-mapReduce.txt index 1da9c4bd3..dc3d3b098 100644 --- a/docs/reference/method/MongoDBCollection-mapReduce.txt +++ b/docs/reference/method/MongoDBCollection-mapReduce.txt @@ -92,7 +92,9 @@ each state. var_dump($pop); }; -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(stdClass)#2293 (2) { ["_id"]=> diff --git a/docs/reference/method/MongoDBCollection-rename.txt b/docs/reference/method/MongoDBCollection-rename.txt index 23a9290c3..a40555f21 100644 --- a/docs/reference/method/MongoDBCollection-rename.txt +++ b/docs/reference/method/MongoDBCollection-rename.txt @@ -61,7 +61,9 @@ database to ``places``: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#9 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBCollection-replaceOne.txt b/docs/reference/method/MongoDBCollection-replaceOne.txt index ba43452b8..9bb3d30cd 100644 --- a/docs/reference/method/MongoDBCollection-replaceOne.txt +++ b/docs/reference/method/MongoDBCollection-replaceOne.txt @@ -77,7 +77,9 @@ The following example replaces the document with ``restaurant_id`` of printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Matched 1 document(s) Modified 1 document(s) diff --git a/docs/reference/method/MongoDBCollection-updateMany.txt b/docs/reference/method/MongoDBCollection-updateMany.txt index bd72fdf9c..65f1fb01c 100644 --- a/docs/reference/method/MongoDBCollection-updateMany.txt +++ b/docs/reference/method/MongoDBCollection-updateMany.txt @@ -67,7 +67,9 @@ The following example updates all of the documents with the ``borough`` of printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Matched 5656 document(s) Modified 5656 document(s) diff --git a/docs/reference/method/MongoDBCollection-updateOne.txt b/docs/reference/method/MongoDBCollection-updateOne.txt index bed657f92..d7fbd1573 100644 --- a/docs/reference/method/MongoDBCollection-updateOne.txt +++ b/docs/reference/method/MongoDBCollection-updateOne.txt @@ -69,7 +69,9 @@ The following example updates one document with the ``restaurant_id`` of printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Matched 1 document(s) Modified 1 document(s) diff --git a/docs/reference/method/MongoDBDatabase-command.txt b/docs/reference/method/MongoDBDatabase-command.txt index 63ddeeaa2..84b581785 100644 --- a/docs/reference/method/MongoDBDatabase-command.txt +++ b/docs/reference/method/MongoDBDatabase-command.txt @@ -57,7 +57,9 @@ result document: var_dump($c->toArray()[0]); -The output would resemble:: +The output would resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#11 (1) { ["storage":"ArrayObject":private]=> @@ -81,7 +83,9 @@ multiple result documents: var_dump($c->toArray()); -The output would resemble:: +The output would resemble: + +.. code-block:: none array(3) { [0]=> diff --git a/docs/reference/method/MongoDBDatabase-createCollection.txt b/docs/reference/method/MongoDBDatabase-createCollection.txt index a3e74ef5c..d640f3d19 100644 --- a/docs/reference/method/MongoDBDatabase-createCollection.txt +++ b/docs/reference/method/MongoDBDatabase-createCollection.txt @@ -79,7 +79,9 @@ database with document validation criteria: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#11 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBDatabase-drop.txt b/docs/reference/method/MongoDBDatabase-drop.txt index bcf6ca88a..eae1bb6b8 100644 --- a/docs/reference/method/MongoDBDatabase-drop.txt +++ b/docs/reference/method/MongoDBDatabase-drop.txt @@ -58,7 +58,9 @@ The following example drops the ``test`` database: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#8 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBDatabase-dropCollection.txt b/docs/reference/method/MongoDBDatabase-dropCollection.txt index fbc005b86..2b58785aa 100644 --- a/docs/reference/method/MongoDBDatabase-dropCollection.txt +++ b/docs/reference/method/MongoDBDatabase-dropCollection.txt @@ -58,7 +58,9 @@ The following example drops the ``users`` collection in the ``test`` database: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#8 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBDatabase-getDatabaseName.txt b/docs/reference/method/MongoDBDatabase-getDatabaseName.txt index 6ff9dcb96..6e3abd966 100644 --- a/docs/reference/method/MongoDBDatabase-getDatabaseName.txt +++ b/docs/reference/method/MongoDBDatabase-getDatabaseName.txt @@ -39,6 +39,8 @@ The following example prints the name of a database object: echo $db->getDatabaseName(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none test diff --git a/docs/reference/method/MongoDBDatabase-getReadConcern.txt b/docs/reference/method/MongoDBDatabase-getReadConcern.txt index fa277d884..4b02a1dd9 100644 --- a/docs/reference/method/MongoDBDatabase-getReadConcern.txt +++ b/docs/reference/method/MongoDBDatabase-getReadConcern.txt @@ -41,7 +41,9 @@ Example var_dump($database->getReadConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadConcern)#5 (1) { ["level"]=> diff --git a/docs/reference/method/MongoDBDatabase-getReadPreference.txt b/docs/reference/method/MongoDBDatabase-getReadPreference.txt index c70b40268..5001455c7 100644 --- a/docs/reference/method/MongoDBDatabase-getReadPreference.txt +++ b/docs/reference/method/MongoDBDatabase-getReadPreference.txt @@ -42,7 +42,9 @@ Example var_dump($database->getReadPreference()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadPreference)#5 (1) { ["mode"]=> diff --git a/docs/reference/method/MongoDBDatabase-getTypeMap.txt b/docs/reference/method/MongoDBDatabase-getTypeMap.txt index bc1688d63..d06c67779 100644 --- a/docs/reference/method/MongoDBDatabase-getTypeMap.txt +++ b/docs/reference/method/MongoDBDatabase-getTypeMap.txt @@ -45,7 +45,9 @@ Example var_dump($database->getTypeMap()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(3) { ["root"]=> diff --git a/docs/reference/method/MongoDBDatabase-getWriteConcern.txt b/docs/reference/method/MongoDBDatabase-getWriteConcern.txt index 31b0ded51..55ea09f4d 100644 --- a/docs/reference/method/MongoDBDatabase-getWriteConcern.txt +++ b/docs/reference/method/MongoDBDatabase-getWriteConcern.txt @@ -42,7 +42,9 @@ Example var_dump($database->getWriteConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\WriteConcern)#5 (2) { ["w"]=> diff --git a/docs/reference/method/MongoDBDatabase-listCollectionNames.txt b/docs/reference/method/MongoDBDatabase-listCollectionNames.txt index 86872bbbc..b6eaa4ce5 100644 --- a/docs/reference/method/MongoDBDatabase-listCollectionNames.txt +++ b/docs/reference/method/MongoDBDatabase-listCollectionNames.txt @@ -52,7 +52,9 @@ The following example lists all of the collections in the ``test`` database: var_dump($collectionName); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(11) "restaurants" string(5) "users" @@ -77,7 +79,9 @@ in the ``test`` database: var_dump($collectionName); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(11) "restaurants" string(6) "restos" diff --git a/docs/reference/method/MongoDBDatabase-listCollections.txt b/docs/reference/method/MongoDBDatabase-listCollections.txt index cfaff6c3d..421b6cab4 100644 --- a/docs/reference/method/MongoDBDatabase-listCollections.txt +++ b/docs/reference/method/MongoDBDatabase-listCollections.txt @@ -51,7 +51,9 @@ The following example lists all of the collections in the ``test`` database: var_dump($collectionInfo); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\CollectionInfo)#3 (2) { ["name"]=> @@ -94,7 +96,9 @@ in the ``test`` database: var_dump($collectionInfo); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\CollectionInfo)#3 (2) { ["name"]=> diff --git a/docs/reference/method/MongoDBDatabase-modifyCollection.txt b/docs/reference/method/MongoDBDatabase-modifyCollection.txt index 43eb2d259..8fe9245c6 100644 --- a/docs/reference/method/MongoDBDatabase-modifyCollection.txt +++ b/docs/reference/method/MongoDBDatabase-modifyCollection.txt @@ -63,7 +63,9 @@ The following example changes the expiration time of a TTL collection in the var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(stdClass)#2779 { ["expireAfterSeconds_old"]=> diff --git a/docs/reference/method/MongoDBDatabase-renameCollection.txt b/docs/reference/method/MongoDBDatabase-renameCollection.txt index 558443195..8bbe5b8e9 100644 --- a/docs/reference/method/MongoDBDatabase-renameCollection.txt +++ b/docs/reference/method/MongoDBDatabase-renameCollection.txt @@ -61,7 +61,9 @@ database to ``places``: var_dump($result); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#8 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBDatabase__get.txt b/docs/reference/method/MongoDBDatabase__get.txt index c41e3981d..280e931da 100644 --- a/docs/reference/method/MongoDBDatabase__get.txt +++ b/docs/reference/method/MongoDBDatabase__get.txt @@ -35,7 +35,7 @@ Behavior The selected collection inherits options such as read preference and type mapping from the :phpclass:`Database ` object. If you wish to -override any options, use the :phpmethod:`MongoDB\\Database::selectCollection` +override any options, use the :phpmethod:`MongoDB\\Database::selectCollection()` method. .. note:: @@ -43,7 +43,7 @@ method. To select collections whose names contain special characters, such as ``.``, use complex syntax, as in ``$database->{'that.database'}``. - Alternatively, :phpmethod:`MongoDB\\Database::selectCollection` supports + Alternatively, :phpmethod:`MongoDB\\Database::selectCollection()` supports selecting collections whose names contain special characters. Examples diff --git a/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt b/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt index 3d8e6ebcf..2f2aa5da1 100644 --- a/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-downloadToStream.txt @@ -54,7 +54,9 @@ Examples var_dump(stream_get_contents($destination, -1, 0)); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(6) "foobar" diff --git a/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt b/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt index a505e115c..a37134a4a 100644 --- a/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt +++ b/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt @@ -58,7 +58,9 @@ Examples var_dump(stream_get_contents($destination, -1, 0)); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(6) "foobar" diff --git a/docs/reference/method/MongoDBGridFSBucket-find.txt b/docs/reference/method/MongoDBGridFSBucket-find.txt index c7418cede..6b3c7728b 100644 --- a/docs/reference/method/MongoDBGridFSBucket-find.txt +++ b/docs/reference/method/MongoDBGridFSBucket-find.txt @@ -75,7 +75,9 @@ Examples var_dump($cursor->toArray()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(1) { [0]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-findOne.txt b/docs/reference/method/MongoDBGridFSBucket-findOne.txt index 7b6fcc8fc..a72de457e 100644 --- a/docs/reference/method/MongoDBGridFSBucket-findOne.txt +++ b/docs/reference/method/MongoDBGridFSBucket-findOne.txt @@ -78,7 +78,9 @@ Examples var_dump($fileDocument); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#3004 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt b/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt index 0452de0a7..52ea92497 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getBucketName.txt @@ -37,6 +37,8 @@ Examples var_dump($bucket->getBucketName()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(2) "fs" diff --git a/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt b/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt index f592030a2..16116e562 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getChunkSizeBytes.txt @@ -39,6 +39,8 @@ Examples var_dump($bucket->getChunkSizeBytes()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none int(261120) diff --git a/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt b/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt index fa5be8322..36dbd8a59 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getChunksCollection.txt @@ -39,6 +39,8 @@ Examples var_dump((string) $bucket->getChunksCollection()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(14) "test.fs.chunks" diff --git a/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt b/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt index b270b7b57..0b6dd8e0b 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getDatabaseName.txt @@ -37,7 +37,9 @@ Examples var_dump($bucket->getDatabaseName()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(4) "test" diff --git a/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt b/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt index 052bc79c9..b9dca55ad 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt @@ -54,7 +54,9 @@ Examples fclose($stream); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#4956 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt b/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt index 976843b4d..4e1c68b48 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt @@ -55,7 +55,9 @@ Examples fclose($stream); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\BSON\ObjectId)#3005 (1) { ["oid"]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt b/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt index de4196b2f..57813ad6d 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getFilesCollection.txt @@ -41,7 +41,9 @@ Examples var_dump($filesCollection->getCollectionName()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(8) "fs.files" diff --git a/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt b/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt index 00517d220..d9c0a8e2a 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt @@ -42,7 +42,9 @@ Example var_dump($bucket->getReadConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadConcern)#3 (1) { ["level"]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt b/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt index 94003eea7..532a6e23e 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getReadPreference.txt @@ -43,7 +43,9 @@ Example var_dump($bucket->getReadPreference()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\ReadPreference)#3 (1) { ["mode"]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt b/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt index cd9c4a1be..7d9a309a3 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getTypeMap.txt @@ -46,7 +46,9 @@ Example var_dump($bucket->getTypeMap()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(3) { ["root"]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt b/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt index 1b5577e6c..b77f1f00c 100644 --- a/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt +++ b/docs/reference/method/MongoDBGridFSBucket-getWriteConcern.txt @@ -43,7 +43,9 @@ Example var_dump($bucket->getWriteConcern()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Driver\WriteConcern)#3 (2) { ["w"]=> diff --git a/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt b/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt index 663a69c95..85f2150a3 100644 --- a/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-openDownloadStream.txt @@ -55,7 +55,9 @@ Examples var_dump(stream_get_contents($downloadStream)); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(6) "foobar" diff --git a/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt b/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt index f796fee03..cb3a336ee 100644 --- a/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt +++ b/docs/reference/method/MongoDBGridFSBucket-openDownloadStreamByName.txt @@ -57,7 +57,9 @@ Examples var_dump(stream_get_contents($bucket->openDownloadStreamByName('filename'))); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(6) "foobar" diff --git a/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt b/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt index b27420f20..348b325f4 100644 --- a/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-openUploadStream.txt @@ -56,7 +56,9 @@ Examples $downloadStream = $bucket->openDownloadStreamByName('filename'); var_dump(stream_get_contents($downloadStream)); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(6) "foobar" diff --git a/docs/reference/method/MongoDBGridFSBucket-rename.txt b/docs/reference/method/MongoDBGridFSBucket-rename.txt index a2fbfe32d..888d1ae3f 100644 --- a/docs/reference/method/MongoDBGridFSBucket-rename.txt +++ b/docs/reference/method/MongoDBGridFSBucket-rename.txt @@ -50,6 +50,8 @@ Examples var_dump(stream_get_contents($bucket->openDownloadStreamByName('b'))); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none string(6) "foobar" diff --git a/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt b/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt index fd2eceee7..2487554dd 100644 --- a/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt +++ b/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt @@ -60,7 +60,9 @@ Examples var_dump($id); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\BSON\ObjectId)#3009 (1) { ["oid"]=> diff --git a/docs/reference/method/MongoDBGridFSBucket__construct.txt b/docs/reference/method/MongoDBGridFSBucket__construct.txt index 5eeee5fc7..c6c309bb3 100644 --- a/docs/reference/method/MongoDBGridFSBucket__construct.txt +++ b/docs/reference/method/MongoDBGridFSBucket__construct.txt @@ -53,7 +53,9 @@ Examples var_dump($bucket); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\GridFS\Bucket)#3053 (2) { ["bucketName"]=> diff --git a/docs/reference/method/MongoDBMapReduceResult-getCounts.txt b/docs/reference/method/MongoDBMapReduceResult-getCounts.txt index c2feab0ca..35c738ddc 100644 --- a/docs/reference/method/MongoDBMapReduceResult-getCounts.txt +++ b/docs/reference/method/MongoDBMapReduceResult-getCounts.txt @@ -45,7 +45,9 @@ This example reports the count statistics for a map-reduce operation. var_dump($result->getCounts()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(4) { ["input"]=> diff --git a/docs/reference/method/MongoDBMapReduceResult-getExecutionTimeMS.txt b/docs/reference/method/MongoDBMapReduceResult-getExecutionTimeMS.txt index 06c5b012b..05b6bbc17 100644 --- a/docs/reference/method/MongoDBMapReduceResult-getExecutionTimeMS.txt +++ b/docs/reference/method/MongoDBMapReduceResult-getExecutionTimeMS.txt @@ -46,7 +46,9 @@ This example reports the execution time for a map-reduce operation. var_dump($result->getExecutionTimeMS()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none int(244) diff --git a/docs/reference/method/MongoDBMapReduceResult-getIterator.txt b/docs/reference/method/MongoDBMapReduceResult-getIterator.txt index b58040288..cb459cde6 100644 --- a/docs/reference/method/MongoDBMapReduceResult-getIterator.txt +++ b/docs/reference/method/MongoDBMapReduceResult-getIterator.txt @@ -15,7 +15,7 @@ Definition .. phpmethod:: MongoDB\\MapReduceResult::getIterator() - Returns a php:`Traversable `, which may be used to iterate + Returns a :php:`Traversable `, which may be used to iterate through the results of the map-reduce operation. .. code-block:: php @@ -49,7 +49,9 @@ This example iterates through the results of a map-reduce operation. var_dump($population); }; -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(stdClass)#2293 (2) { ["_id"]=> diff --git a/docs/reference/method/MongoDBMapReduceResult-getTiming.txt b/docs/reference/method/MongoDBMapReduceResult-getTiming.txt index 75ab53939..0492b3bec 100644 --- a/docs/reference/method/MongoDBMapReduceResult-getTiming.txt +++ b/docs/reference/method/MongoDBMapReduceResult-getTiming.txt @@ -51,7 +51,9 @@ for a map-reduce operation. var_dump($result->getTiming()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(5) { ["mapTime"]=> diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt b/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt index 99a7d082e..dcd8e703f 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getCappedMax.txt @@ -52,7 +52,9 @@ Examples var_dump($info->getCappedMax()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none int(100) diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt b/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt index 1d94a4042..62732aa47 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getCappedSize.txt @@ -52,7 +52,9 @@ Examples var_dump($info->getCappedSize()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none int(1048576) diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt b/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt index 4c0e4aa31..4fa22dc00 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getIdIndex.txt @@ -49,7 +49,9 @@ Examples var_dump($info->getIdIndex()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(4) { ["v"]=> diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt b/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt index 40068e3b4..4d4f19ff3 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getInfo.txt @@ -44,7 +44,9 @@ Examples var_dump($info->getInfo()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(1) { ["readOnly"]=> diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getName.txt b/docs/reference/method/MongoDBModelCollectionInfo-getName.txt index 76af1fa9b..d3104af82 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getName.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getName.txt @@ -38,7 +38,9 @@ Examples echo $info->getName(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none foo diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt b/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt index 4c7fabe55..3ffac1db8 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getOptions.txt @@ -46,7 +46,9 @@ Examples var_dump($info->getOptions()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(2) { ["capped"]=> diff --git a/docs/reference/method/MongoDBModelCollectionInfo-getType.txt b/docs/reference/method/MongoDBModelCollectionInfo-getType.txt index b900efed3..9fdf5c990 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-getType.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-getType.txt @@ -40,7 +40,9 @@ Examples echo $info->getType(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none collection diff --git a/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt b/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt index 15957ae80..a6067e0a5 100644 --- a/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt +++ b/docs/reference/method/MongoDBModelCollectionInfo-isCapped.txt @@ -50,7 +50,9 @@ Examples var_dump($info->isCapped()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none bool(true) diff --git a/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt b/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt index a2524a4b1..6f82a77ab 100644 --- a/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt +++ b/docs/reference/method/MongoDBModelDatabaseInfo-getName.txt @@ -37,7 +37,9 @@ Examples echo $info->getName(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none foo diff --git a/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt b/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt index d42f23ff5..8c3a0b0b4 100644 --- a/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt +++ b/docs/reference/method/MongoDBModelDatabaseInfo-getSizeOnDisk.txt @@ -37,7 +37,9 @@ Examples var_dump($info->getSizeOnDisk()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none int(1048576) diff --git a/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt b/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt index ae25e67f2..1c68299ea 100644 --- a/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt +++ b/docs/reference/method/MongoDBModelDatabaseInfo-isEmpty.txt @@ -37,7 +37,9 @@ Examples var_dump($info->isEmpty()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none bool(true) diff --git a/docs/reference/method/MongoDBModelIndexInfo-getKey.txt b/docs/reference/method/MongoDBModelIndexInfo-getKey.txt index 1a115f9cc..ff416f919 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-getKey.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-getKey.txt @@ -41,7 +41,9 @@ Examples var_dump($info->getKey()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none array(1) { ["x"]=> diff --git a/docs/reference/method/MongoDBModelIndexInfo-getName.txt b/docs/reference/method/MongoDBModelIndexInfo-getName.txt index 97ad45fae..ba4fa55e2 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-getName.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-getName.txt @@ -42,7 +42,9 @@ Examples echo $info->getName(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none x_1 diff --git a/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt b/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt index f4a64bb66..f4bb7a596 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-getNamespace.txt @@ -40,7 +40,9 @@ Examples echo $info->getNamespace(); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none foo.bar diff --git a/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt b/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt index 728f38858..96a227706 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-getVersion.txt @@ -39,7 +39,9 @@ Examples var_dump($info->getVersion()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none int(1) diff --git a/docs/reference/method/MongoDBModelIndexInfo-is2dSphere.txt b/docs/reference/method/MongoDBModelIndexInfo-is2dSphere.txt index a6bb398be..017e6e7bd 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-is2dSphere.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-is2dSphere.txt @@ -46,7 +46,9 @@ Examples } } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none pos_2dsphere has 2dsphereIndexVersion: 3 diff --git a/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt b/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt index a2d9a028b..a2ee99e55 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt @@ -46,7 +46,9 @@ Examples } } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none pos_geoHaystack_x_1 has bucketSize: 5 diff --git a/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt b/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt index 5bbe4dea4..533793c9e 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-isSparse.txt @@ -41,7 +41,9 @@ Examples var_dump($info->isSparse()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none bool(true) diff --git a/docs/reference/method/MongoDBModelIndexInfo-isText.txt b/docs/reference/method/MongoDBModelIndexInfo-isText.txt index 083335968..7e0488f5b 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-isText.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-isText.txt @@ -45,7 +45,9 @@ Examples } } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none name_text has default language: english diff --git a/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt b/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt index a3e70d036..a33a22b96 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-isTtl.txt @@ -41,7 +41,9 @@ Examples var_dump($info->isTtl()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none bool(true) diff --git a/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt b/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt index 30cf1ece5..ef61e7c3a 100644 --- a/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt +++ b/docs/reference/method/MongoDBModelIndexInfo-isUnique.txt @@ -41,7 +41,9 @@ Examples var_dump($info->isUnique()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none bool(true) diff --git a/docs/tutorial/collation.txt b/docs/tutorial/collation.txt index 76df18fe7..28225db01 100644 --- a/docs/tutorial/collation.txt +++ b/docs/tutorial/collation.txt @@ -196,7 +196,7 @@ A collection called ``names`` contains the following documents: { "_id" : 4, "first_name" : "Jürgen" } The following :phpmethod:`findOneAndUpdate() -` operation on the collection does not +` operation on the collection does not specify a collation. .. code-block:: php @@ -214,7 +214,7 @@ Because ``Gunter`` is lexically first in the collection, the above operation returns no results and updates no documents. Consider the same :phpmethod:`findOneAndUpdate() -` operation but with a collation +` operation but with a collation specified, which uses the locale ``de@collation=phonebook``. .. note:: @@ -349,7 +349,7 @@ Aggregation ~~~~~~~~~~~ To use collation with an :phpmethod:`aggregate() -` operation, specify a collation in the +` operation, specify a collation in the aggregation options. The following aggregation example uses a collection called ``names`` and groups diff --git a/docs/tutorial/commands.txt b/docs/tutorial/commands.txt index 88ce5ec9a..68a5ec268 100644 --- a/docs/tutorial/commands.txt +++ b/docs/tutorial/commands.txt @@ -52,7 +52,9 @@ in the ``restos`` collection in the ``test`` database: var_dump($results); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#27 (1) { ["storage":"ArrayObject":private]=> @@ -240,7 +242,9 @@ custom read preference: var_dump($cursor->toArray()[0]); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#8 (1) { ["storage":"ArrayObject":private]=> @@ -273,7 +277,9 @@ document, or access the first result in the array, as in the following: var_dump($cursor->toArray()[0]); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#2 (1) { ["storage":"ArrayObject":private]=> @@ -307,7 +313,9 @@ iterating through the cursor returned by the ``listCollections`` command using a } The output would then be a list of the values for the ``name`` key, for -instance:: +instance: + +.. code-block:: none persons posts diff --git a/docs/tutorial/crud.txt b/docs/tutorial/crud.txt index 1e9f95e2e..a5c0d431c 100644 --- a/docs/tutorial/crud.txt +++ b/docs/tutorial/crud.txt @@ -61,7 +61,9 @@ The following example inserts a document while specifying the value for the var_dump($insertOneResult->getInsertedId()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Inserted 1 document(s) int(1) @@ -113,7 +115,9 @@ The following example searches for the document with ``_id`` of ``"94301"``: var_dump($document); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#13 (1) { ["storage":"ArrayObject":private]=> @@ -175,7 +179,9 @@ specified city and state values: echo $document['_id'], "\n"; } -The output would resemble:: +The output would resemble: + +.. code-block:: none 07302 07304 @@ -231,7 +237,9 @@ returned. It also limits the results to 5 documents. var_dump($restaurant); }; -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#10 (1) { ["storage":"ArrayObject":private]=> @@ -325,7 +333,9 @@ five most populous zip codes in the United States: printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none 60623: CHICAGO, IL 11226: BROOKLYN, NY @@ -358,7 +368,9 @@ name starts with "garden" and the state is Texas: printf("%s: %s, %s\n", $document['_id'], $document['city'], $document['state']); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none 78266: GARDEN RIDGE, TX 79739: GARDEN CITY, TX @@ -422,7 +434,9 @@ with them: printf("%s has %d zip codes\n", $state['_id'], $state['count']); } -The output would then resemble:: +The output would then resemble: + +.. code-block:: none TX has 1671 zip codes NY has 1595 zip codes @@ -472,7 +486,9 @@ is ``"ny"`` to include a ``country`` field set to ``"us"``: Since the update operation uses the :phpmethod:`MongoDB\\Collection::updateOne()` method, which updates the first -document to match the filter criteria, the results would then resemble:: +document to match the filter criteria, the results would then resemble: + +.. code-block:: none Matched 1 document(s) Modified 1 document(s) @@ -498,7 +514,9 @@ value, as in this example: printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); The number of matched documents and the number of *modified* documents would -therefore not be equal, and the output from the operation would resemble:: +therefore not be equal, and the output from the operation would resemble: + +.. code-block:: none Matched 1 document(s) Modified 0 document(s) @@ -521,7 +539,7 @@ updates to perform. The :phpmethod:`MongoDB\\Collection::updateMany()` reference describes each parameter in detail. The following example inserts three documents into an empty ``users`` collection -in the ``test`` database and then uses the :query:`$set` operator to update the +in the ``test`` database and then uses the :update:`$set` operator to update the documents matching the filter criteria to include the ``country`` field with value ``"us"``: @@ -547,7 +565,9 @@ If an update operation results in no change to a document, such as setting the value of the field to its current value, the number of modified documents can be less than the number of *matched* documents. Since the update document with ``name`` of ``"Bob"`` results in no changes to the document, the output of the -operation therefore resembles:: +operation therefore resembles: + +.. code-block:: none Matched 3 document(s) Modified 2 document(s) @@ -573,7 +593,7 @@ replacement document that will replace the original document in MongoDB. The :phpmethod:`MongoDB\\Collection::replaceOne()` reference describes each parameter in detail. -.. important:: +.. important:: Replacement operations replace all of the fields in a document except the ``_id`` value. To avoid accidentally overwriting or deleting desired fields, @@ -600,12 +620,14 @@ the ``test`` database, and then replaces that document with a new one: printf("Matched %d document(s)\n", $updateResult->getMatchedCount()); printf("Modified %d document(s)\n", $updateResult->getModifiedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Matched 1 document(s) Modified 1 document(s) -.. seealso:: +.. seealso:: - :phpmethod:`MongoDB\\Collection::replaceOne()` - :phpmethod:`MongoDB\\Collection::findOneAndReplace()` @@ -649,7 +671,9 @@ the ``upsert`` option set to ``true`` and an empty ``users`` collection in the var_dump($upsertedDocument); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Matched 0 document(s) Modified 0 document(s) @@ -705,7 +729,9 @@ value is ``"ny"``: printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Deleted 1 document(s) @@ -739,7 +765,9 @@ value is ``"ny"``: printf("Deleted %d document(s)\n", $deleteResult->getDeletedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Deleted 2 document(s) diff --git a/docs/tutorial/custom-types.txt b/docs/tutorial/custom-types.txt index 574604302..3c1dd1239 100644 --- a/docs/tutorial/custom-types.txt +++ b/docs/tutorial/custom-types.txt @@ -152,7 +152,9 @@ back to ``LocalDateTime``. var_dump($document->date->toDateTime()); ?> -Which outputs:: +Which outputs: + +.. code-block:: none object(stdClass)#1 (1) { ["date"]=> diff --git a/docs/tutorial/decimal128.txt b/docs/tutorial/decimal128.txt index a94d0ea5e..3bdab8f13 100644 --- a/docs/tutorial/decimal128.txt +++ b/docs/tutorial/decimal128.txt @@ -48,7 +48,9 @@ field of a collection named ``inventory``: var_dump($item); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#9 (1) { ["storage":"ArrayObject":private]=> @@ -86,7 +88,9 @@ The following example adds two ``Decimal128`` values and creates a new var_dump($sum); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\BSON\Decimal128)#4 (1) { ["dec"]=> @@ -111,7 +115,9 @@ obtain the expected result: var_dump($sum); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none object(MongoDB\BSON\Decimal128)#4 (1) { ["dec"]=> diff --git a/docs/tutorial/example-data.txt b/docs/tutorial/example-data.txt index cf3230952..920de5877 100644 --- a/docs/tutorial/example-data.txt +++ b/docs/tutorial/example-data.txt @@ -9,7 +9,7 @@ Some examples in this documentation use example data fixtures from `primer-dataset.json `_. Importing the dataset into MongoDB can be done in several ways. The following -example imports the `zips.json` file into a `test.zips` collection: +example imports the ``zips.json`` file into a ``test.zips`` collection: :php:`driver ` directly: .. code-block:: php @@ -32,7 +32,9 @@ example imports the `zips.json` file into a `test.zips` collection: $result = $manager->executeBulkWrite('test.zips', $bulk); printf("Inserted %d documents\n", $result->getInsertedCount()); -The output would then resemble:: +The output would then resemble: + +.. code-block:: none Inserted 29353 documents diff --git a/docs/tutorial/gridfs.txt b/docs/tutorial/gridfs.txt index 81f6d2639..4eb7e1566 100644 --- a/docs/tutorial/gridfs.txt +++ b/docs/tutorial/gridfs.txt @@ -23,7 +23,7 @@ Creating a GridFS Bucket You can construct a GridFS bucket using the PHP extension's :php:`MongoDB\\Driver\\Manager ` class, or select a bucket from the |php-library|'s :phpclass:`MongoDB\\Database` class via the -:phpmethod:`selectGridFSBucket() ` +:phpmethod:`selectGridFSBucket() ` method. The bucket can be constructed with various options: @@ -112,9 +112,9 @@ number. Revision numbers are used to distinguish between files sharing the same ``filename`` metadata field, ordered by date of upload (i.e. the ``uploadDate`` metadata field). The ``revision`` option accepted by :phpmethod:`openDownloadStreamByName() -` and +` and :phpmethod:`downloadToStreamByName() -` can be positive or negative. +` can be positive or negative. A positive ``revision`` number may be used to select files in order of the oldest upload date. A revision of ``0`` would denote the file with the oldest @@ -157,7 +157,7 @@ You can delete a GridFS file by its ``_id``. Finding File Metadata --------------------- -The :phpmethod:`find() ` method allows you to +The :phpmethod:`find() ` method allows you to retrieve documents from the GridFS files collection, which contain metadata about the GridFS files. @@ -173,7 +173,7 @@ Accessing File Metadata for an Existing Stream ---------------------------------------------- The :phpmethod:`getFileDocumentForStream() -` method may be used to get +` method may be used to get the file document for an existing readable or writable GridFS stream. .. code-block:: php @@ -193,16 +193,16 @@ the file document for an existing readable or writable GridFS stream. Since the file document for a writable stream is not committed to MongoDB until the stream is closed, :phpmethod:`getFileDocumentForStream() - ` can only return an + ` can only return an in-memory document, which will be missing some fields (e.g. ``length``, ``md5``). The :phpmethod:`getFileIdForStream() -` method may be used to get the +` method may be used to get the ``_id`` for an existing readable or writable GridFS stream. This is a convenience for accessing the ``_id`` property of the object returned by :phpmethod:`getFileDocumentForStream() -`. +`. .. code-block:: php diff --git a/docs/tutorial/indexes.txt b/docs/tutorial/indexes.txt index 0ffe7bdb9..e04d43653 100644 --- a/docs/tutorial/indexes.txt +++ b/docs/tutorial/indexes.txt @@ -31,7 +31,7 @@ Create indexes with the :phpmethod:`MongoDB\\Collection::createIndex()` or reference for more details about each method. The following example creates an ascending index on the ``state`` field using -the :phpmethod:`createIndex() ` method: +the :phpmethod:`createIndex() ` method: .. code-block:: php @@ -45,7 +45,9 @@ the :phpmethod:`createIndex() ` method: When you create an index, the method returns its name, which is automatically generated from its specification. The above example would output something -similar to:: +similar to: + +.. code-block:: none string(7) "state_1" @@ -71,7 +73,9 @@ The following example lists all indexes in the ``zips`` collection in the var_dump($indexInfo); } -The output would resemble:: +The output would resemble: + +.. code-block:: none object(MongoDB\Model\IndexInfo)#10 (4) { ["v"]=> @@ -120,7 +124,9 @@ The following example drops a single index by its name, ``state_1``: var_dump($result); -The operation's output would resemble:: +The operation's output would resemble: + +.. code-block:: none object(MongoDB\Model\BSONDocument)#11 (1) { ["storage":"ArrayObject":private]=> diff --git a/docs/tutorial/modeling-bson-data.txt b/docs/tutorial/modeling-bson-data.txt index 38f44769f..24486d1e1 100644 --- a/docs/tutorial/modeling-bson-data.txt +++ b/docs/tutorial/modeling-bson-data.txt @@ -167,7 +167,7 @@ directly serialized. This is similar to how enums are handled by :php:`json_encode() `. Round-tripping a backed enum through BSON requires special handling. In the -following example, the `bsonUnserialize()` method in the class containing the +following example, the ``bsonUnserialize()`` method in the class containing the enum is responsible for converting the value back to an enum case: .. code-block:: php diff --git a/docs/upgrade.txt b/docs/upgrade.txt index 4a67b7fbe..ff1bc90ee 100644 --- a/docs/upgrade.txt +++ b/docs/upgrade.txt @@ -263,7 +263,7 @@ equivalent method(s) in the new driver. * - ``MongoCollection::group()`` - Not implemented. Use :phpmethod:`MongoDB\\Database::command()`. See - `Group Command Helper`_ for an example. + :ref:`Group Command Helper ` for an example. * - ``MongoCollection::insert()`` - :phpmethod:`MongoDB\\Collection::insertOne()` @@ -332,8 +332,8 @@ MongoCollection::save() Removed ``MongoCollection::save()``, which was syntactic sugar for an insert or upsert operation, has been removed in favor of explicitly using -:phpmethod:`MongoDB\\Collection::insertOne` or -:phpmethod:`MongoDB\\Collection::replaceOne` (with the ``upsert`` option). +:phpmethod:`MongoDB\\Collection::insertOne()` or +:phpmethod:`MongoDB\\Collection::replaceOne()` (with the ``upsert`` option). While the ``save`` method does have its uses for interactive environments, such as the ``mongo`` shell, it was intentionally excluded from the @@ -345,6 +345,8 @@ handle the returned :phpclass:`MongoDB\\InsertOneResult` or inadvertent and potentially dangerous :manual:`full-document replacements `. +.. _group-command-helper: + Group Command Helper ~~~~~~~~~~~~~~~~~~~~ From edba8b21c2af74ca86421cc4fc7f51357a251a4d Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Dec 2022 08:49:04 -0500 Subject: [PATCH 238/321] PHPLIB-1049: AWS authentication with temporary credentials in CSFLE (#1014) * PHPLIB-866: Use separate group for AWS on-demand credential prose test This isolates testing with unset AWS credentials in order to avoid potential conflicts with other tests, such as temporary credential testing for PHPLIB-1049. * Refactor CSFLE env var access in legacy test runner This copies over the getEnv() helper from the unified test runner, which allows us to remove additional checking and skips. * Include unified spec tests in "csfle" group * PHPLIB-1049: AWS authentication with temporary credentials in CSFLE Spec tests were previously synced and only needed to be unskipped. Co-authored-by: Andreas Braun --- .evergreen/config.yml | 54 +++++++++++-- .evergreen/run-tests.sh | 4 + CONTRIBUTING.md | 3 + .../ClientSideEncryptionSpecTest.php | 3 +- tests/SpecTests/Context.php | 81 ++++++++++++------- tests/UnifiedSpecTests/UnifiedSpecTest.php | 1 + 6 files changed, 110 insertions(+), 36 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 22d17b9b0..fa27100a2 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -284,6 +284,9 @@ functions: ${PREPARE_SHELL} export AWS_ACCESS_KEY_ID="${client_side_encryption_aws_access_key_id}" export AWS_SECRET_ACCESS_KEY="${client_side_encryption_aws_secret_access_key}" + export AWS_TEMP_ACCESS_KEY_ID="${client_side_encryption_aws_temp_access_key_id}" + export AWS_TEMP_SECRET_ACCESS_KEY="${client_side_encryption_aws_temp_secret_access_key_key}" + export AWS_TEMP_SESSION_TOKEN="${client_side_encryption_aws_temp_session_token}" export AZURE_TENANT_ID="${client_side_encryption_azure_tenant_id}" export AZURE_CLIENT_ID="${client_side_encryption_azure_client_id}" export AZURE_CLIENT_SECRET="${client_side_encryption_azure_client_secret}" @@ -328,6 +331,9 @@ functions: ${PREPARE_SHELL} export AWS_ACCESS_KEY_ID="${client_side_encryption_aws_access_key_id}" export AWS_SECRET_ACCESS_KEY="${client_side_encryption_aws_secret_access_key}" + export AWS_TEMP_ACCESS_KEY_ID="${client_side_encryption_aws_temp_access_key_id}" + export AWS_TEMP_SECRET_ACCESS_KEY="${client_side_encryption_aws_temp_secret_access_key_key}" + export AWS_TEMP_SESSION_TOKEN="${client_side_encryption_aws_temp_session_token}" export AZURE_TENANT_ID="${client_side_encryption_azure_tenant_id}" export AZURE_CLIENT_ID="${client_side_encryption_azure_client_id}" export AZURE_CLIENT_SECRET="${client_side_encryption_azure_client_secret}" @@ -455,6 +461,36 @@ functions: - key: client_side_encryption_kmip_endpoint value: localhost:5698 + "set aws temp creds": + - command: shell.exec + params: + shell: bash + script: |- + set -o errexit + + export AWS_ACCESS_KEY_ID="${client_side_encryption_aws_access_key_id}" + export AWS_SECRET_ACCESS_KEY="${client_side_encryption_aws_secret_access_key}" + export AWS_DEFAULT_REGION="us-east-1" + + pushd ${DRIVERS_TOOLS}/.evergreen/csfle + . ./activate_venv.sh + . ./set-temp-creds.sh + popd + + if [ -z "$CSFLE_AWS_TEMP_ACCESS_KEY_ID" ]; then + echo "Failed to set AWS temporary credentials!" + exit 1 + fi + + cat < aws-expansion.yml + client_side_encryption_aws_temp_access_key_id: "$CSFLE_AWS_TEMP_ACCESS_KEY_ID" + client_side_encryption_aws_temp_secret_access_key_key: "$CSFLE_AWS_TEMP_SECRET_ACCESS_KEY" + client_side_encryption_aws_temp_session_token: "$CSFLE_AWS_TEMP_SESSION_TOKEN" + EOT + - command: expansions.update + params: + file: aws-expansion.yml + pre: - func: "fetch source" - func: "prepare resources" @@ -513,6 +549,7 @@ tasks: vars: TOPOLOGY: "server" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" - name: "test-replica_set" @@ -522,6 +559,7 @@ tasks: vars: TOPOLOGY: "replica_set" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" - name: "test-sharded_cluster" @@ -531,6 +569,7 @@ tasks: vars: TOPOLOGY: "sharded_cluster" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" - name: "test-atlas-data-lake" @@ -547,6 +586,7 @@ tasks: AUTH: "auth" REQUIRE_API_VERSION: "yes" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" vars: API_VERSION: "1" @@ -559,6 +599,7 @@ tasks: TOPOLOGY: "server" ORCHESTRATION_FILE: "versioned-api-testing.json" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" vars: TESTS: "versioned-api" @@ -568,6 +609,7 @@ tasks: commands: - func: "create serverless instance" - func: "start kms servers" + - func: "set aws temp creds" - func: "run serverless tests" - name: "test-loadBalanced" @@ -580,6 +622,7 @@ tasks: SSL: "yes" - func: "start load balancer" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" vars: # Note: loadBalanced=true should already be appended to SINGLE_MONGOS_LB_URI @@ -593,12 +636,13 @@ tasks: vars: TOPOLOGY: "replica_set" - func: "start kms servers" + - func: "set aws temp creds" - func: "run tests" vars: SKIP_CRYPT_SHARED: "yes" TESTS: "csfle" - - name: "test-without_aws_credentials" + - name: "test-without_aws_creds" commands: - func: "bootstrap mongo-orchestration" vars: @@ -608,7 +652,7 @@ tasks: vars: client_side_encryption_aws_access_key_id: "" client_side_encryption_aws_secret_access_key: "" - TESTS: "csfle" + TESTS: "csfle-without-aws-creds" # }}} @@ -879,8 +923,8 @@ buildvariants: - name: "test-skip_crypt_shared" # Run CSFLE tests without AWS credentials (for "On-demand AWS Credentials" prose test) -- matrix_name: "test-csfle-without_aws_credentials" +- matrix_name: "test-csfle-without_aws_creds" matrix_spec: { "os": "debian11", "mongodb-versions": "6.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" } - display_name: "CSFLE without_aws_credentials - ${mongodb-versions}" + display_name: "CSFLE without_aws_creds - ${mongodb-versions}" tasks: - - name: "test-without_aws_credentials" + - name: "test-without_aws_creds" diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index c56e86b66..ac707e9a1 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -76,6 +76,10 @@ case "$TESTS" in php vendor/bin/simple-phpunit $PHPUNIT_OPTS --group csfle ;; + csfle-without-aws-creds) + php vendor/bin/simple-phpunit $PHPUNIT_OPTS --group csfle-without-aws-creds + ;; + versioned-api) php vendor/bin/simple-phpunit $PHPUNIT_OPTS --group versioned-api ;; diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5bbe3993d..7ed676815 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -90,6 +90,9 @@ The following environment variables are used for [CSFLE testing](https://github. * `AWS_ACCESS_KEY_ID` * `AWS_SECRET_ACCESS_KEY` + * `AWS_TEMP_ACCESS_KEY_ID` + * `AWS_TEMP_SECRET_ACCESS_KEY` + * `AWS_TEMP_SESSION_TOKEN` * `AZURE_TENANT_ID` * `AZURE_CLIENT_ID` * `AZURE_CLIENT_SECRET` diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php index 32361f755..fcab1de58 100644 --- a/tests/SpecTests/ClientSideEncryptionSpecTest.php +++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php @@ -63,8 +63,6 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase /** @var array */ private static $incompleteTests = [ - 'awsTemporary: Insert a document with auto encryption using the AWS provider with temporary credentials' => 'Not yet implemented (PHPC-1751)', - 'awsTemporary: Insert with invalid temporary credentials' => 'Not yet implemented (PHPC-1751)', 'azureKMS: Insert a document with auto encryption using Azure KMS provider' => 'RHEL platform is missing Azure root certificate (PHPLIB-619)', 'explain: Explain a find with deterministic encryption' => 'crypt_shared does not add apiVersion field to explain commands (PHPLIB-947, SERVER-69564)', 'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)', @@ -1641,6 +1639,7 @@ static function (self $test, Client $setupClient, ClientEncryption $clientEncryp * Prose test 15: On-demand AWS Credentials * * @see https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#on-demand-aws-credentials + * @group csfle-without-aws-creds * @testWith [true] * [false] */ diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php index 0ead3e961..226f94286 100644 --- a/tests/SpecTests/Context.php +++ b/tests/SpecTests/Context.php @@ -15,6 +15,8 @@ use function array_keys; use function getenv; use function implode; +use function PHPUnit\Framework\assertLessThanOrEqual; +use function sprintf; /** * Execution context for spec tests. @@ -86,10 +88,26 @@ public static function fromClientSideEncryption(stdClass $test, $databaseName, $ $autoEncryptionOptions = (array) $clientOptions['autoEncryptOpts'] + ['keyVaultNamespace' => 'keyvault.datakeys']; unset($clientOptions['autoEncryptOpts']); + // Ensure test doesn't specify conflicting options for AWS + $countAws = (isset($autoEncryptionOptions['kmsProviders']->aws) ? 1 : 0); + $countAws += (isset($autoEncryptionOptions['kmsProviders']->awsTemporary) ? 1 : 0); + $countAws += (isset($autoEncryptionOptions['kmsProviders']->awsTemporaryNoSessionToken) ? 1 : 0); + assertLessThanOrEqual(1, $countAws, 'aws, awsTemporary, and awsTemporaryNoSessionToken are mutually exclusive'); + if (isset($autoEncryptionOptions['kmsProviders']->aws)) { $autoEncryptionOptions['kmsProviders']->aws = self::getAWSCredentials(); } + if (isset($autoEncryptionOptions['kmsProviders']->awsTemporary)) { + unset($autoEncryptionOptions['kmsProviders']->awsTemporary); + $autoEncryptionOptions['kmsProviders']->aws = self::getAWSTempCredentials(true); + } + + if (isset($autoEncryptionOptions['kmsProviders']->awsTemporaryNoSessionToken)) { + unset($autoEncryptionOptions['kmsProviders']->awsTemporaryNoSessionToken); + $autoEncryptionOptions['kmsProviders']->aws = self::getAWSTempCredentials(false); + } + if (isset($autoEncryptionOptions['kmsProviders']->azure)) { $autoEncryptionOptions['kmsProviders']->azure = self::getAzureCredentials(); } @@ -227,59 +245,53 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti public static function getAWSCredentials(): array { - if (! getenv('AWS_ACCESS_KEY_ID') || ! getenv('AWS_SECRET_ACCESS_KEY')) { - Assert::markTestSkipped('Please configure AWS credentials to use AWS KMS provider.'); - } - return [ - 'accessKeyId' => getenv('AWS_ACCESS_KEY_ID'), - 'secretAccessKey' => getenv('AWS_SECRET_ACCESS_KEY'), + 'accessKeyId' => static::getEnv('AWS_ACCESS_KEY_ID'), + 'secretAccessKey' => static::getEnv('AWS_SECRET_ACCESS_KEY'), ]; } - public static function getAzureCredentials(): array + public static function getAWSTempCredentials(bool $withSessionToken): array { - if (! getenv('AZURE_TENANT_ID') || ! getenv('AZURE_CLIENT_ID') || ! getenv('AZURE_CLIENT_SECRET')) { - Assert::markTestSkipped('Please configure Azure credentials to use Azure KMS provider.'); + $awsTempCredentials = [ + 'accessKeyId' => static::getEnv('AWS_TEMP_ACCESS_KEY_ID'), + 'secretAccessKey' => static::getEnv('AWS_TEMP_SECRET_ACCESS_KEY'), + ]; + + if ($withSessionToken) { + $awsTempCredentials['sessionToken'] = static::getEnv('AWS_TEMP_SESSION_TOKEN'); } + return $awsTempCredentials; + } + + public static function getAzureCredentials(): array + { return [ - 'tenantId' => getenv('AZURE_TENANT_ID'), - 'clientId' => getenv('AZURE_CLIENT_ID'), - 'clientSecret' => getenv('AZURE_CLIENT_SECRET'), + 'tenantId' => static::getEnv('AZURE_TENANT_ID'), + 'clientId' => static::getEnv('AZURE_CLIENT_ID'), + 'clientSecret' => static::getEnv('AZURE_CLIENT_SECRET'), ]; } public static function getKmipEndpoint(): string { - if (! getenv('KMIP_ENDPOINT')) { - Assert::markTestSkipped('Please configure KMIP endpoint to use KMIP KMS provider.'); - } - - return getenv('KMIP_ENDPOINT'); + return static::getEnv('KMIP_ENDPOINT'); } public static function getKmsTlsOptions(): array { - if (! getenv('KMS_TLS_CA_FILE') || ! getenv('KMS_TLS_CERTIFICATE_KEY_FILE')) { - Assert::markTestSkipped('Please configure KMS TLS options.'); - } - return [ - 'tlsCAFile' => getenv('KMS_TLS_CA_FILE'), - 'tlsCertificateKeyFile' => getenv('KMS_TLS_CERTIFICATE_KEY_FILE'), + 'tlsCAFile' => static::getEnv('KMS_TLS_CA_FILE'), + 'tlsCertificateKeyFile' => static::getEnv('KMS_TLS_CERTIFICATE_KEY_FILE'), ]; } public static function getGCPCredentials(): array { - if (! getenv('GCP_EMAIL') || ! getenv('GCP_PRIVATE_KEY')) { - Assert::markTestSkipped('Please configure GCP credentials to use GCP KMS provider.'); - } - return [ - 'email' => getenv('GCP_EMAIL'), - 'privateKey' => getenv('GCP_PRIVATE_KEY'), + 'email' => static::getEnv('GCP_EMAIL'), + 'privateKey' => static::getEnv('GCP_PRIVATE_KEY'), ]; } @@ -453,6 +465,17 @@ private static function createTestClient(?string $uri = null, array $options = [ return FunctionalTestCase::createTestClient($uri, $options, $driverOptions); } + private static function getEnv(string $name): string + { + $value = getenv($name); + + if ($value === false) { + Assert::markTestSkipped(sprintf('Environment variable "%s" is not defined', $name)); + } + + return $value; + } + private function prepareGridFSBucketOptions(array $options, $bucketPrefix) { if ($bucketPrefix !== null) { diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 9a4fea23f..9972905b4 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -103,6 +103,7 @@ public function provideChangeStreamsTests() /** * @dataProvider provideClientSideEncryptionTests + * @group csfle */ public function testClientSideEncryption(UnifiedTestCase $test): void { From b2d90a93b95d7cbc4337311eb2ff29ef49834698 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Wed, 14 Dec 2022 08:49:49 -0500 Subject: [PATCH 239/321] PHPLIB-1051: Skip example tests when API version is required (#1015) The example files create their client objects independently of the test suite, which injects an API version when it's required. This fixes an issue originally introduced in b309cf8e4deb784705543addace0959ad13c0afc. --- tests/ExamplesTest.php | 4 ++++ tests/FunctionalTestCase.php | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/ExamplesTest.php b/tests/ExamplesTest.php index d90f53dd6..79747533a 100644 --- a/tests/ExamplesTest.php +++ b/tests/ExamplesTest.php @@ -15,6 +15,10 @@ public function setUp(): void $this->markTestSkipped('Examples are not tested on sharded clusters.'); } + if ($this->isApiVersionRequired()) { + $this->markTestSkipped('Examples are not tested with when the server requires specifying an API version.'); + } + self::createTestClient()->dropDatabase('test'); } diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index 76d81fb4e..08fa9eb5e 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -388,6 +388,26 @@ protected function getServerStorageEngine(?ReadPreference $readPreference = null throw new UnexpectedValueException('Could not determine server storage engine'); } + /** + * Returns whether clients must specify an API version by checking the + * requireApiVersion server parameter. + */ + protected function isApiVersionRequired(): bool + { + try { + $cursor = $this->manager->executeCommand( + 'admin', + new Command(['getParameter' => 1, 'requireApiVersion' => 1]) + ); + + $document = current($cursor->toArray()); + } catch (CommandException $e) { + return false; + } + + return isset($document->requireApiVersion) && $document->requireApiVersion === true; + } + protected function isEnterprise(): bool { $buildInfo = $this->getPrimaryServer()->executeCommand( From 47398a576080ffff9443b7062b9f5911ac8a7f31 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 19 Dec 2022 17:37:11 +0800 Subject: [PATCH 240/321] Refer Windows users to GitHub releases instead of PECL for DLLs (#1016) As of ext-mongodb 1.15.0 (PHPC-2143), DLLs are attached to GitHub release notes. --- docs/faq.txt | 9 ++++++--- docs/tutorial/install-php-library.txt | 17 +++++++++-------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/docs/faq.txt b/docs/faq.txt index ff9acc025..72801e161 100644 --- a/docs/faq.txt +++ b/docs/faq.txt @@ -75,8 +75,8 @@ wrap the script in ``
`` tags to properly format its output:
 Loading an Incompatible DLL on Windows
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-PECL builds Windows binaries for various combinations of PHP version,
-thread-safety (TS or NTS), and architecture (x86 or x64). Failure to select the
+Windows binaries are available for various combinations of PHP version,
+thread safety (TS or NTS), and architecture (x86 or x64). Failure to select the
 correct binary will result in an error when attempting to load the extension DLL
 at runtime:
 
@@ -88,7 +88,7 @@ Ensure that you have downloaded a DLL that corresponds to the following PHP
 runtime properties:
 
 - PHP version (``PHP_VERSION``)
-- Thread-safety (``PHP_ZTS``)
+- Thread safety (``PHP_ZTS``)
 - Architecture (``PHP_INT_SIZE``)
 
 In addition to the aforementioned constants, these properties can also be
@@ -96,6 +96,9 @@ inferred from :php:`phpinfo() `. If your system has multiple PHP
 runtimes installed, double-check that you are examining the ``phpinfo()`` output
 for the correct environment.
 
+The aforementioned ``detect-extension`` script can also be used to determine the
+appropriate DLL for your PHP environment.
+
 Server Selection Failures
 -------------------------
 
diff --git a/docs/tutorial/install-php-library.txt b/docs/tutorial/install-php-library.txt
index f4087cba0..af409c360 100644
--- a/docs/tutorial/install-php-library.txt
+++ b/docs/tutorial/install-php-library.txt
@@ -41,17 +41,18 @@ file:
 
    extension=mongodb.so
 
-Windows users can download precompiled binaries of the extension from
-`PECL `_. After extracting the
-``php_mongodb.dll`` file to PHP's extension directory, add the following line to
-your ``php.ini`` file:
+Windows users can download precompiled binaries of the extension from its
+`GitHub releases `__.
+After downloading the appropriate archive for your PHP environment, extract the
+``php_mongodb.dll`` file to PHP's extension directory and add the following line
+to your ``php.ini`` file:
 
 .. code-block:: ini
 
    extension=php_mongodb.dll
 
-Additional considerations for Windows are discussed in the
-:php:`Windows installation documentation `.
+See :php:`Installing the MongoDB PHP Driver on Windows `
+for additional information.
 
 Installing the Library
 ----------------------
@@ -85,8 +86,8 @@ Manual Installation Without Composer
 
 While not recommended, you may also manually install the library using a source
 archive attached to the
-`GitHub releases `_. When
-installing the library without Composer, you must ensure that all library
+`GitHub releases `__.
+When installing the library without Composer, you must ensure that all library
 classes *and* functions are loaded for your application:
 
 #. If you are using a `PSR-4 `_ autoloader,

From fc4a8790b2aba86dde09005657bfd15f03ee236a Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Thu, 22 Dec 2022 11:20:37 +0800
Subject: [PATCH 241/321] PHPLIB-1038: Use activate-kmstlsvenv.sh and
 find-python3.sh in Evergreen config (#1017)

* PHPLIB-1038: Use activate-kmstlsvenv.sh in Evergreen config

* Use find-python3.sh in "create serverless instance" function

PYTHON3_BINARY was never declared. The original code only worked thanks to the shebang in mongodl.py.

* find-python3.sh and activate-kmstlsvenv.sh require bash

* Remove Windows-specific logic from "create serverless instance" function

Serverless is only tested on Debian hosts
---
 .evergreen/config.yml | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index fa27100a2..68f10fdf9 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -214,34 +214,37 @@ functions:
         file: src/serverless-expansion.yml
     - command: shell.exec
       params:
-        shell: "bash"
+        shell: bash
         script: |
           ${PREPARE_SHELL}
-          
+
           if [ -z "${SERVERLESS_MONGODB_VERSION}" ]; then
             echo "expected SERVERLESS_MONGODB_VERSION to be set"
             exit 1
           fi
-          
+
+          . ${DRIVERS_TOOLS}/.evergreen/find-python3.sh
+          PYTHON_BINARY="$(find_python3)" || exit 1
+
           # Download the enterprise server download for current platform to $MONGODB_BINARIES.
           # This is required for tests that need mongocryptd.
           # $MONGODB_BINARIES is added to the $PATH in fetch-source.
-          ${PYTHON3_BINARY} $DRIVERS_TOOLS/.evergreen/mongodl.py \
+          ${PYTHON_BINARY} ${DRIVERS_TOOLS}/.evergreen/mongodl.py \
               --component archive \
               --version ${SERVERLESS_MONGODB_VERSION} \
               --edition enterprise \
               --out $MONGODB_BINARIES \
               --strip-path-components 2
-          
+
           # Download the crypt_shared dynamic library for the current platform.
-          ${PYTHON3_BINARY} $DRIVERS_TOOLS/.evergreen/mongodl.py \
+          ${PYTHON_BINARY} ${DRIVERS_TOOLS}/.evergreen/mongodl.py \
             --component crypt_shared \
             --version ${SERVERLESS_MONGODB_VERSION} \
             --edition enterprise \
             --out . \
             --only "**/mongo_crypt_v1.*" \
             --strip-path-components 1
-          
+
           # Find the crypt_shared library file in the current directory and set the CRYPT_SHARED_LIB_PATH to
           # the path of that file. Only look for .so, .dll, or .dylib files to prevent matching any other
           # downloaded files.
@@ -249,12 +252,7 @@ functions:
             -name 'mongo_crypt_v1.so' -o \
             -name 'mongo_crypt_v1.dll' -o \
             -name 'mongo_crypt_v1.dylib')"
-          
-          # If we're on Windows, convert the "cygdrive" path to Windows-style paths.
-          if [ "Windows_NT" = "$OS" ]; then
-              CRYPT_SHARED_LIB_PATH=$(cygpath -m $CRYPT_SHARED_LIB_PATH)
-          fi
-          
+
           echo "CRYPT_SHARED_LIB_PATH: $CRYPT_SHARED_LIB_PATH" >> crypt-expansion.yml
 
     # Load the expansion file to make an evergreen variable with the current unique version
@@ -429,18 +427,20 @@ functions:
     - command: shell.exec
       # Init venv without background:true to install dependencies
       params:
+        shell: bash
         script: |-
           set -o errexit
           cd ${DRIVERS_TOOLS}/.evergreen/csfle
-          . ./activate_venv.sh
+          . ./activate-kmstlsvenv.sh
     - command: shell.exec
       params:
         background: true
+        shell: bash
         # Use different ports for KMS HTTP servers to avoid conflicts with load balancers
         script: |-
           set -o errexit
           cd ${DRIVERS_TOOLS}/.evergreen/csfle
-          . ./activate_venv.sh
+          . ./activate-kmstlsvenv.sh
           python -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8100 &
           python -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8101 &
           python -u kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/server.pem --port 8102 --require_client_cert &
@@ -473,7 +473,7 @@ functions:
           export AWS_DEFAULT_REGION="us-east-1"
 
           pushd ${DRIVERS_TOOLS}/.evergreen/csfle
-          . ./activate_venv.sh
+          . ./activate-kmstlsvenv.sh
           . ./set-temp-creds.sh
           popd
 

From 49f3e3dcadd8d8014f011d308116bdd3d96ad350 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Fri, 23 Dec 2022 03:31:51 +0100
Subject: [PATCH 242/321] Simplify `composer install` in Github Actions (#1018)

For reference see https://github.com/ramsey/composer-install

No need to add `--no-interaction` and `--no-progress` explicitly and caching is done internally.
---
 .github/workflows/coding-standards.yml | 11 +++--------
 .github/workflows/static-analysis.yml  | 11 +++--------
 .github/workflows/tests.yml            | 11 +++--------
 3 files changed, 9 insertions(+), 24 deletions(-)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index 06b999ced..7ce7ca500 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -54,15 +54,10 @@ jobs:
       - name: "Show driver information"
         run: "php --ri mongodb"
 
-      - name: "Cache dependencies installed with Composer"
-        uses: "actions/cache@v2"
-        with:
-          path: "~/.composer/cache"
-          key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
-          restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
-
       - name: "Install dependencies with Composer"
-        run: "composer install --no-interaction --no-progress --no-suggest"
+        uses: "ramsey/composer-install@2.2.0"
+        with:
+          composer-options: "--no-suggest"
 
       # The -q option is required until phpcs v4 is released
       - name: "Run PHP_CodeSniffer"
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index a1a09ca43..52c49a04b 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -54,15 +54,10 @@ jobs:
       - name: "Show driver information"
         run: "php --ri mongodb"
 
-      - name: "Cache dependencies installed with Composer"
-        uses: "actions/cache@v2"
-        with:
-          path: "~/.composer/cache"
-          key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
-          restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
-
       - name: "Install dependencies with Composer"
-        run: "composer install --no-interaction --no-progress --no-suggest"
+        uses: "ramsey/composer-install@2.2.0"
+        with:
+          composer-options: "--no-suggest"
 
       - name: "Run Psalm"
         run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index e3372df4c..319ee5088 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -99,15 +99,10 @@ jobs:
       - name: "Show driver information"
         run: "php --ri mongodb"
 
-      - name: "Cache dependencies installed with composer"
-        uses: "actions/cache@v2"
+      - name: "Install dependencies with Composer"
+        uses: "ramsey/composer-install@2.2.0"
         with:
-          path: "~/.composer/cache"
-          key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}"
-          restore-keys: "php-${{ matrix.php-version }}-composer-locked-"
-
-      - name: "Install dependencies with composer"
-        run: "composer update --no-interaction --no-progress"
+          composer-options: "--no-suggest"
 
       - name: "Run PHPUnit"
         run: "vendor/bin/simple-phpunit -v"

From 27a5d03e6ba5f4933e155dff6e486e631eacd4ce Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Tue, 27 Dec 2022 03:08:49 +0100
Subject: [PATCH 243/321] Fix typo in Bucket::openDownloadStreamByName() doc
 block (#1023)

---
 src/GridFS/Bucket.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php
index 67ad9ffd8..259b35608 100644
--- a/src/GridFS/Bucket.php
+++ b/src/GridFS/Bucket.php
@@ -494,7 +494,7 @@ public function openDownloadStream($id)
     }
 
     /**
-     * Opens a readable stream stream to read a GridFS file, which is selected
+     * Opens a readable stream to read a GridFS file, which is selected
      * by name and revision.
      *
      * Supported options:

From 75b99dc97f4bf1fe2a881a36fc75fad05d31f474 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 28 Dec 2022 14:53:32 +0100
Subject: [PATCH 244/321] Specify export-ignore rules in .gitattributes to
 shrink the dist package (#1020)

---
 .gitattributes | 13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 .gitattributes

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..eb9a2b8f3
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+.* export-ignore
+*.md export-ignore
+tests export-ignore
+docs export-ignore
+examples export-ignore
+mongo-orchestration export-ignore
+tools export-ignore
+Makefile export-ignore
+phpcs.xml.dist export-ignore
+phpunit.evergreen.xml export-ignore
+phpunit.xml.dist export-ignore
+psalm.xml.dist export-ignore
+psalm-baseline.xml export-ignore

From dea346e48c8b8b44ae193371b3e225a3a979274e Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Mon, 9 Jan 2023 16:52:09 +0800
Subject: [PATCH 245/321] PHPLIB-1055: Various small documentation fixes
 (#1024)

* Use literals instead of RC/RP/WC constants for conciseness

* PHPLIB-1057: Note that geoHaystack was removed in MongoDB 5.0+

* Use correct boolean type in updateMany() example code

* Better clarify Database::command() purpose and examples

Also fixes two long-standing syntax errors in the example code

* Revise command tutorial and sync with command() docs

Remove the geoNear example since the command itself was removed in MongoDB 4.2.
---
 .../method/MongoDBClient-selectCollection.txt |   2 +-
 .../method/MongoDBClient-selectDatabase.txt   |   2 +-
 .../MongoDBCollection-getReadConcern.txt      |   2 +-
 .../method/MongoDBCollection-updateMany.txt   |   2 +-
 .../method/MongoDBCollection-withOptions.txt  |   2 +-
 .../method/MongoDBDatabase-command.txt        |  23 +-
 .../method/MongoDBDatabase-getReadConcern.txt |   2 +-
 .../MongoDBDatabase-selectCollection.txt      |   2 +-
 .../MongoDBDatabase-selectGridFSBucket.txt    |   2 +-
 .../method/MongoDBDatabase-withOptions.txt    |   2 +-
 .../MongoDBGridFSBucket-getReadConcern.txt    |   2 +-
 .../MongoDBModelIndexInfo-isGeoHaystack.txt   |   8 +-
 docs/tutorial/commands.txt                    | 329 ++++--------------
 13 files changed, 103 insertions(+), 277 deletions(-)

diff --git a/docs/reference/method/MongoDBClient-selectCollection.txt b/docs/reference/method/MongoDBClient-selectCollection.txt
index 34a251988..88828c29b 100644
--- a/docs/reference/method/MongoDBClient-selectCollection.txt
+++ b/docs/reference/method/MongoDBClient-selectCollection.txt
@@ -72,7 +72,7 @@ with a custom read preference:
        'test',
        'users',
        [
-           'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY),
+           'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'),
        ]
    );
 
diff --git a/docs/reference/method/MongoDBClient-selectDatabase.txt b/docs/reference/method/MongoDBClient-selectDatabase.txt
index 73ecc2b95..a556a06ae 100644
--- a/docs/reference/method/MongoDBClient-selectDatabase.txt
+++ b/docs/reference/method/MongoDBClient-selectDatabase.txt
@@ -71,7 +71,7 @@ preference:
    $db = $client->selectDatabase(
        'test',
        [
-           'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY),
+           'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'),
        ]
    );
 
diff --git a/docs/reference/method/MongoDBCollection-getReadConcern.txt b/docs/reference/method/MongoDBCollection-getReadConcern.txt
index 2a40efedf..37873d0f9 100644
--- a/docs/reference/method/MongoDBCollection-getReadConcern.txt
+++ b/docs/reference/method/MongoDBCollection-getReadConcern.txt
@@ -36,7 +36,7 @@ Example
    selectCollection('test', 'users', [
-      'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY),
+      'readConcern' => new MongoDB\Driver\ReadConcern('majority'),
    ]);
 
    var_dump($collection->getReadConcern());
diff --git a/docs/reference/method/MongoDBCollection-updateMany.txt b/docs/reference/method/MongoDBCollection-updateMany.txt
index 65f1fb01c..73092e78d 100644
--- a/docs/reference/method/MongoDBCollection-updateMany.txt
+++ b/docs/reference/method/MongoDBCollection-updateMany.txt
@@ -61,7 +61,7 @@ The following example updates all of the documents with the ``borough`` of
 
    $updateResult = $collection->updateMany(
        [ 'borough' => 'Queens' ],
-       [ '$set' => [ 'active' => 'True' ]]
+       [ '$set' => [ 'active' => true ]]
    );
 
    printf("Matched %d document(s)\n", $updateResult->getMatchedCount());
diff --git a/docs/reference/method/MongoDBCollection-withOptions.txt b/docs/reference/method/MongoDBCollection-withOptions.txt
index 92e09f6e3..a68a5fec0 100644
--- a/docs/reference/method/MongoDBCollection-withOptions.txt
+++ b/docs/reference/method/MongoDBCollection-withOptions.txt
@@ -52,7 +52,7 @@ preference:
    $collection = (new MongoDB\Client)->selectCollection('test', 'restaurants');
 
    $newCollection = $sourceCollection->withOptions([
-       'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY),
+       'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'),
    ]);
 
 See Also
diff --git a/docs/reference/method/MongoDBDatabase-command.txt b/docs/reference/method/MongoDBDatabase-command.txt
index 84b581785..d442541cf 100644
--- a/docs/reference/method/MongoDBDatabase-command.txt
+++ b/docs/reference/method/MongoDBDatabase-command.txt
@@ -15,7 +15,9 @@ Definition
 
 .. phpmethod:: MongoDB\\Database::command()
 
-   Execute a :manual:`command ` on the database.
+   Execute a :manual:`command ` on the database. This is
+   generally used to execute commands that do not have a corresponding helper
+   method within the library.
 
    .. code-block:: php
 
@@ -43,9 +45,10 @@ Errors/Exceptions
 Example
 -------
 
-The following example executes a :manual:`ping
-` command, which returns a cursor with a single
-result document:
+Most database commands return a single result document, which can be obtained by
+converting the returned cursor to an array and accessing its first element. The
+following example executes a :manual:`ping ` command
+and prints its result document:
 
 .. code-block:: php
 
@@ -55,7 +58,7 @@ result document:
 
    $cursor = $database->command(['ping' => 1]);
 
-   var_dump($c->toArray()[0]);
+   var_dump($cursor->toArray()[0]);
 
 The output would resemble:
 
@@ -69,9 +72,11 @@ The output would resemble:
      }
    }
 
-The following example executes a :manual:`listCollections
-` command, which returns a cursor with
-multiple result documents:
+Some database commands return a cursor with multiple results. The following
+example executes :manual:`listCollections `,
+which returns a cursor containing a result document for each collection in the
+``test`` database. Note that this example is illustrative; applications would
+generally use :phpmethod:`MongoDB\\Database::listCollections()` in practice.
 
 .. code-block:: php
 
@@ -81,7 +86,7 @@ multiple result documents:
 
    $cursor = $database->command(['listCollections' => 1]);
 
-   var_dump($c->toArray());
+   var_dump($cursor->toArray());
 
 The output would resemble:
 
diff --git a/docs/reference/method/MongoDBDatabase-getReadConcern.txt b/docs/reference/method/MongoDBDatabase-getReadConcern.txt
index 4b02a1dd9..56568aa4b 100644
--- a/docs/reference/method/MongoDBDatabase-getReadConcern.txt
+++ b/docs/reference/method/MongoDBDatabase-getReadConcern.txt
@@ -36,7 +36,7 @@ Example
    selectDatabase('test', [
-      'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY),
+      'readConcern' => new MongoDB\Driver\ReadConcern('majority'),
    ]);
 
    var_dump($database->getReadConcern());
diff --git a/docs/reference/method/MongoDBDatabase-selectCollection.txt b/docs/reference/method/MongoDBDatabase-selectCollection.txt
index 6294e1a75..fb17687b4 100644
--- a/docs/reference/method/MongoDBDatabase-selectCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-selectCollection.txt
@@ -71,7 +71,7 @@ database with a custom read preference:
    $users = $db->selectCollection(
        'users',
        [
-           'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY),
+           'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'),
        ]
    );
 
diff --git a/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt b/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt
index 9c63fdf7c..f93906276 100644
--- a/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt
+++ b/docs/reference/method/MongoDBDatabase-selectGridFSBucket.txt
@@ -71,7 +71,7 @@ database with a custom read preference:
 
    $imagesBucket = $db->selectGridFSBucket([
        'bucketName' => 'images',
-       'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY),
+       'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'),
    ]);
 
 See Also
diff --git a/docs/reference/method/MongoDBDatabase-withOptions.txt b/docs/reference/method/MongoDBDatabase-withOptions.txt
index 9bc0a82ea..6f732eacc 100644
--- a/docs/reference/method/MongoDBDatabase-withOptions.txt
+++ b/docs/reference/method/MongoDBDatabase-withOptions.txt
@@ -52,7 +52,7 @@ preference:
    $db = (new MongoDB\Client)->test;
 
    $newDb = $db->withOptions([
-       'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_SECONDARY),
+       'readPreference' => new MongoDB\Driver\ReadPreference('primaryPreferred'),
    ]);
 
 See Also
diff --git a/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt b/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt
index d9c0a8e2a..7b12c0513 100644
--- a/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-getReadConcern.txt
@@ -37,7 +37,7 @@ Example
 
    $database = (new MongoDB\Client)->selectDatabase('test');
    $bucket = $database->selectGridFSBucket([
-      'readConcern' => new MongoDB\Driver\ReadConcern(MongoDB\Driver\ReadConcern::MAJORITY),
+      'readConcern' => new MongoDB\Driver\ReadConcern('majority'),
    ]);
 
    var_dump($bucket->getReadConcern());
diff --git a/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt b/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt
index a2ee99e55..97f844f10 100644
--- a/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt
+++ b/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt
@@ -17,13 +17,17 @@ Definition
 
 .. phpmethod:: MongoDB\\Model\\IndexInfo::isGeoHaystack()
 
-   Return whether the index is a :manual:`geoHaystack
-   ` index.
+   Return whether the index is a :manual:`geoHaystack `
+   index.
 
    .. code-block:: php
 
       function isGeoHaystack(): boolean
 
+   .. note::
+
+      MongoDB 5.0 and later no longer supports geoHaystack indexes.
+
 Return Values
 -------------
 
diff --git a/docs/tutorial/commands.txt b/docs/tutorial/commands.txt
index 68a5ec268..bccf74626 100644
--- a/docs/tutorial/commands.txt
+++ b/docs/tutorial/commands.txt
@@ -20,17 +20,18 @@ The |php-library| provides helper methods across the :phpclass:`Client
 :phpmethod:`MongoDB\\Database::command()` method may be used to run database
 commands that do not have a helper method.
 
-Execute Database Commands
--------------------------
+The :phpmethod:`MongoDB\\Database::command()` method always returns a
+:php:`MongoDB\\Driver\\Cursor ` object, since it must
+support execution of commands that return single result documents *and* multiple
+results via a command cursor.
 
-Basic Command
-~~~~~~~~~~~~~
+Commands That Return a Single Result Document
+---------------------------------------------
 
-To execute a command on a :program:`mongod` instance, use the
-:phpmethod:`MongoDB\\Database::command()` method. For instance, the following
-operation uses the :manual:`geoNear ` command to
-search for the three closest documents to longitude ``-74`` and latitude ``40``
-in the ``restos`` collection in the ``test`` database:
+Most database commands return a single result document, which can be obtained by
+converting the returned cursor to an array and accessing its first element. The
+following example executes a :manual:`ping ` command
+and prints its result document:
 
 .. code-block:: php
 
@@ -38,196 +39,90 @@ in the ``restos`` collection in the ``test`` database:
 
    $database = (new MongoDB\Client)->test;
 
-   $cursor = $database->command([
-       'geoNear' => 'restos',
-       'near' => [
-           'type' => 'Point',
-           'coordinates' => [-74.0, 40.0],
-       ],
-       'spherical' => 'true',
-       'num' => 3,
-   ]);
-
-   $results = $cursor->toArray()[0];
+   $cursor = $database->command(['ping' => 1]);
 
-   var_dump($results);
+   var_dump($cursor->toArray()[0]);
 
-The output would then resemble:
+The output would resemble:
 
 .. code-block:: none
 
-   object(MongoDB\Model\BSONDocument)#27 (1) {
+   object(MongoDB\Model\BSONDocument)#11 (1) {
      ["storage":"ArrayObject":private]=>
-     array(4) {
-       ["waitedMS"]=>
-       int(0)
-       ["results"]=>
-       object(MongoDB\Model\BSONArray)#25 (1) {
-         ["storage":"ArrayObject":private]=>
-         array(3) {
-           [0]=>
-           object(MongoDB\Model\BSONDocument)#14 (1) {
-             ["storage":"ArrayObject":private]=>
-             array(2) {
-               ["dis"]=>
-               float(39463.618389163)
-               ["obj"]=>
-               object(MongoDB\Model\BSONDocument)#13 (1) {
-                 ["storage":"ArrayObject":private]=>
-                 array(3) {
-                   ["_id"]=>
-                   object(MongoDB\BSON\ObjectId)#3 (1) {
-                     ["oid"]=>
-                     string(24) "55cba2486c522cafdb059bed"
-                   }
-                   ["location"]=>
-                   object(MongoDB\Model\BSONDocument)#12 (1) {
-                     ["storage":"ArrayObject":private]=>
-                     array(2) {
-                       ["coordinates"]=>
-                       object(MongoDB\Model\BSONArray)#11 (1) {
-                         ["storage":"ArrayObject":private]=>
-                         array(2) {
-                           [0]=>
-                           float(-74.1641319)
-                           [1]=>
-                           float(39.6686512)
-                         }
-                       }
-                       ["type"]=>
-                       string(5) "Point"
-                     }
-                   }
-                   ["name"]=>
-                   string(32) "Soul Food Kitchen Seafood Heaven"
-                 }
-               }
-             }
-           }
-           [1]=>
-           object(MongoDB\Model\BSONDocument)#19 (1) {
-             ["storage":"ArrayObject":private]=>
-             array(2) {
-               ["dis"]=>
-               float(50686.851650416)
-               ["obj"]=>
-               object(MongoDB\Model\BSONDocument)#18 (1) {
-                 ["storage":"ArrayObject":private]=>
-                 array(3) {
-                   ["_id"]=>
-                   object(MongoDB\BSON\ObjectId)#15 (1) {
-                     ["oid"]=>
-                     string(24) "55cba2476c522cafdb0544df"
-                   }
-                   ["location"]=>
-                   object(MongoDB\Model\BSONDocument)#17 (1) {
-                     ["storage":"ArrayObject":private]=>
-                     array(2) {
-                       ["coordinates"]=>
-                       object(MongoDB\Model\BSONArray)#16 (1) {
-                         ["storage":"ArrayObject":private]=>
-                         array(2) {
-                           [0]=>
-                           float(-74.2566332)
-                           [1]=>
-                           float(40.4109872)
-                         }
-                       }
-                       ["type"]=>
-                       string(5) "Point"
-                     }
-                   }
-                   ["name"]=>
-                   string(20) "Seguine Bagel Bakery"
-                 }
-               }
-             }
-           }
-           [2]=>
-           object(MongoDB\Model\BSONDocument)#24 (1) {
-             ["storage":"ArrayObject":private]=>
-             array(2) {
-               ["dis"]=>
-               float(58398.379630263)
-               ["obj"]=>
-               object(MongoDB\Model\BSONDocument)#23 (1) {
-                 ["storage":"ArrayObject":private]=>
-                 array(3) {
-                   ["_id"]=>
-                   object(MongoDB\BSON\ObjectId)#20 (1) {
-                     ["oid"]=>
-                     string(24) "55cba2476c522cafdb053c92"
-                   }
-                   ["location"]=>
-                   object(MongoDB\Model\BSONDocument)#22 (1) {
-                     ["storage":"ArrayObject":private]=>
-                     array(2) {
-                       ["coordinates"]=>
-                       object(MongoDB\Model\BSONArray)#21 (1) {
-                         ["storage":"ArrayObject":private]=>
-                         array(2) {
-                           [0]=>
-                           float(-74.3731727)
-                           [1]=>
-                           float(40.4404759)
-                         }
-                       }
-                       ["type"]=>
-                       string(5) "Point"
-                     }
-                   }
-                   ["name"]=>
-                   string(17) "Water'S Edge Club"
-                 }
-               }
-             }
-           }
-         }
-       }
-       ["stats"]=>
-       object(MongoDB\Model\BSONDocument)#26 (1) {
-         ["storage":"ArrayObject":private]=>
-         array(5) {
-           ["nscanned"]=>
-           int(25139)
-           ["objectsLoaded"]=>
-           int(25134)
-           ["avgDistance"]=>
-           float(49516.283223281)
-           ["maxDistance"]=>
-           float(58398.379630263)
-           ["time"]=>
-           int(126)
-         }
-       }
+     array(1) {
        ["ok"]=>
        float(1)
      }
    }
 
-Commands with Custom Read Preference
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Commands That Yield Multiple Results
+------------------------------------
+
+Some database commands return a cursor with multiple results. The following
+example executes :manual:`listCollections `,
+which returns a cursor containing a result document for each collection in the
+``test`` database, and iterates through the results using a ``foreach`` loop.
+Note that this example is illustrative; applications would generally use
+:phpmethod:`MongoDB\\Database::listCollections()` in practice.
+
+.. code-block:: php
+
+   test;
+
+   $cursor = $database->command(['listCollections' => 1]);
+
+   foreach ($cursor as $collection) {
+       echo $collection['name'], "\n";
+   }
+
+The output might resemble the following:
+
+.. code-block:: none
+
+   persons
+   posts
+   zips
 
-Some commands, such as :manual:`createUser `, may
-only be executed on a :term:`primary` replica set member or a
-:term:`standalone`.
+.. note::
 
-The command helper methods in the |php-library|, such as
+   At the *protocol* level, commands that yield multiple results via a cursor
+   will return a single result document with the essential ingredients for
+   constructing the cursor (i.e. the cursor's ID, namespace, and an optional
+   first batch of results). If the :php:`MongoDB\Driver\Manager::executeCommand()
+   ` method in the PHP driver detects
+   such a response, it will construct an iterable command cursor and return it
+   instead of the raw result document. If necessary, raw result documents can
+   still be observed using `command monitoring
+   `_.
+
+Specifying a Custom Read Preference
+-----------------------------------
+
+Write commands, such as :manual:`createUser `,
+can only be executed on a writable server (e.g. :term:`primary` replica set
+member). Command helper methods in the |php-library|, such as
 :phpmethod:`MongoDB\\Database::drop()`, know to apply their own :term:`read
 preference` if necessary. However, the :phpmethod:`MongoDB\\Database::command()`
 method is a generic method and defaults to the read preference of the Database
-object on which it is invoked. To execute commands that require a specific read
-preference, specify the read preference in the ``$options`` parameter of the
-method.
+object on which it is invoked. When necessary, the ``readPreference`` option may
+be used to override the default read preference.
 
-The following example adds a user to the ``test`` database and specifies a
-custom read preference:
+The following example connects to a cluster and specifies ``secondaryPreferred``
+as the Client's default read preference. It then specifies a ``primary`` read
+preference when executing the ``createUser`` command on the ``test`` database:
 
 .. code-block:: php
 
    test;
+   $client = new MongoDB\Client(
+      'mongodb+srv://cluster0.example.com',
+      ['readPreference' => 'secondaryPreferred']
+   );
+
+   $client->test;
 
    $cursor = $db->command(
        [
@@ -236,7 +131,7 @@ custom read preference:
            'roles' => ['readWrite'],
        ],
        [
-           'readPreference' => new MongoDB\Driver\ReadPreference(MongoDB\Driver\ReadPreference::RP_PRIMARY),
+           'readPreference' => new MongoDB\Driver\ReadPreference('primary'),
        ]
    );
 
@@ -253,81 +148,3 @@ The output would then resemble:
        float(1)
      }
    }
-
-View Command Results
---------------------
-
-View Single Result Documents
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The :phpmethod:`MongoDB\\Database::command()` method returns a
-:php:`MongoDB\\Driver\\Cursor ` object.
-
-Many MongoDB commands return their responses as a single document. To read the
-command response, you may either iterate on the cursor and access the first
-document, or access the first result in the array, as in the following:
-
-.. code-block:: php
-
-   test;
-
-   $cursor = $database->command(['ping' => 1]);
-
-   var_dump($cursor->toArray()[0]);
-
-The output would then resemble:
-
-.. code-block:: none
-
-   object(MongoDB\Model\BSONDocument)#2 (1) {
-     ["storage":"ArrayObject":private]=>
-     array(1) {
-       ["ok"]=>
-       float(1)
-     }
-   }
-
-Iterate Results from a Cursor
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Some commands, such as :manual:`listCollections
-`, return their results via an iterable
-cursor. To view the results, iterate through the cursor.
-
-The following example lists the collections in the ``test`` database by
-iterating through the cursor returned by the ``listCollections`` command using a
-``foreach`` loop:
-
-.. code-block:: php
-
-   test;
-
-   $cursor = $database->command(['listCollections' => 1]);
-
-   foreach ($cursor as $collection) {
-       echo $collection['name'], "\n";
-   }
-
-The output would then be a list of the values for the ``name`` key, for
-instance:
-
-.. code-block:: none
-
-   persons
-   posts
-   zips
-
-.. note::
-
-   At the *protocol* level, commands that support a cursor return a single
-   result document with the essential ingredients for constructing the command
-   cursor (i.e. the cursor's ID, namespace, and the first batch of results). In
-   the PHP driver implementation, the
-   :php:`MongoDB\Driver\Manager::executeCommand()
-   ` method detects such a result and
-   constructs the iterable command cursor, which is returned rather than the
-   base result document.

From 964e88707810d04bf851031743999c8ee7460dcd Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 10 Jan 2023 18:36:34 +0800
Subject: [PATCH 246/321] PHPLIB-794: Use single/multi-mongos LB URIs when
 available (#1019)

* PHPLIB-794: Use single/multi-mongos LB URIs when available

This ensures MONGODB_SINGLE_MONGOS_LB_URI and MONGODB_MULTI_MONGOS_LB_URI are now set for load balancer tasks in Evergreen and used within the test suite.

Also fixes some bugs in the original getUri() code for reassembling a URL with a single mongos host. Previously, auth credentials were not properly appended (d5b1156d92e883997f3b0a1afea16fcb9870acc2) and a query string could be appended without a slash between the question mark and last host in the seedlist (49d32aa798261f1baec41d81d643680fc323b043).

* Fix static method invocations

* Append TLS options to LB URIs if necessary
---
 .evergreen/config.yml                        |   2 +
 .evergreen/run-tests.sh                      |  25 +++-
 tests/FunctionalTestCase.php                 | 126 +++++++++++--------
 tests/SpecTests/TransactionsSpecTest.php     |   4 +-
 tests/UnifiedSpecTests/UnifiedTestRunner.php |   8 +-
 5 files changed, 98 insertions(+), 67 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 68f10fdf9..be1192e6a 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -301,6 +301,8 @@ functions:
           API_VERSION=${API_VERSION} \
           CRYPT_SHARED_LIB_PATH=${CRYPT_SHARED_LIB_PATH} \
           MONGODB_URI="${MONGODB_URI}" \
+          MONGODB_SINGLE_MONGOS_LB_URI="${SINGLE_MONGOS_LB_URI}" \
+          MONGODB_MULTI_MONGOS_LB_URI="${MULTI_MONGOS_LB_URI}" \
           PHP_VERSION=${PHP_VERSION} \
           SKIP_CRYPT_SHARED=${SKIP_CRYPT_SHARED} \
           SSL=${SSL} \
diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh
index ac707e9a1..df32fb941 100755
--- a/.evergreen/run-tests.sh
+++ b/.evergreen/run-tests.sh
@@ -7,6 +7,8 @@ CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH:-}" # Optional path to crypt_shar
 DRIVER_MONGODB_VERSION=${DRIVER_MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true"
 IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} # Specify "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked.
 MONGODB_URI=${MONGODB_URI:-} # Connection string (including credentials and topology info)
+MONGODB_SINGLE_MONGOS_LB_URI=${MONGODB_SINGLE_MONGOS_LB_URI:-} # Single-mongos LB connection string
+MONGODB_MULTI_MONGOS_LB_URI=${MONGODB_MULTI_MONGOS_LB_URI:-} # Multi-mongos LB connection string
 MONGODB_VERSION=${MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true"
 SKIP_CRYPT_SHARED="${SKIP_CRYPT_SHARED:-no}" # Specify "yes" to ignore CRYPT_SHARED_LIB_PATH. Defaults to "no"
 SSL=${SSL:-no} # Specify "yes" to enable SSL. Defaults to "no"
@@ -44,14 +46,25 @@ fi
 # Enable verbose output to see skipped and incomplete tests
 PHPUNIT_OPTS="${PHPUNIT_OPTS} -v --configuration phpunit.evergreen.xml"
 
-# Determine if MONGODB_URI already has a query string
-SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat)
-
 if [ "$SSL" = "yes" ]; then
+   SSL_OPTS="ssl=true&sslallowinvalidcertificates=true"
+
+   # Determine if MONGODB_URI already has a query string
+   SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat)
+
    if [ -z "$SUFFIX" ]; then
-      MONGODB_URI="${MONGODB_URI}/?ssl=true&sslallowinvalidcertificates=true"
+      MONGODB_URI="${MONGODB_URI}/?${SSL_OPTS}"
    else
-      MONGODB_URI="${MONGODB_URI}&ssl=true&sslallowinvalidcertificates=true"
+      MONGODB_URI="${MONGODB_URI}&${SSL_OPTS}"
+   fi
+
+   # Assume LB URIs already have a query string (e.g. "?loadBalanced=true")
+   if [ -n "${MONGODB_SINGLE_MONGOS_LB_URI}" ]; then
+      MONGODB_SINGLE_MONGOS_LB_URI="${MONGODB_SINGLE_MONGOS_LB_URI}&${SSL_OPTS}"
+   fi
+
+   if [ -n "${MONGODB_MULTI_MONGOS_LB_URI}" ]; then
+      MONGODB_MULTI_MONGOS_LB_URI="${MONGODB_MULTI_MONGOS_LB_URI}&${SSL_OPTS}"
    fi
 fi
 
@@ -65,6 +78,8 @@ export SYMFONY_DEPRECATIONS_HELPER=999999
 export API_VERSION="${API_VERSION}"
 export CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH}"
 export MONGODB_URI="${MONGODB_URI}"
+export MONGODB_SINGLE_MONGOS_LB_URI="${MONGODB_SINGLE_MONGOS_LB_URI}"
+export MONGODB_MULTI_MONGOS_LB_URI="${MONGODB_MULTI_MONGOS_LB_URI}"
 
 # Run the tests, and store the results in a junit result file
 case "$TESTS" in
diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php
index 08fa9eb5e..500bd5263 100644
--- a/tests/FunctionalTestCase.php
+++ b/tests/FunctionalTestCase.php
@@ -20,7 +20,6 @@
 use stdClass;
 use UnexpectedValueException;
 
-use function array_merge;
 use function call_user_func;
 use function count;
 use function current;
@@ -90,63 +89,16 @@ public static function createTestManager(?string $uri = null, array $options = [
 
     public static function getUri($allowMultipleMongoses = false): string
     {
-        $uri = parent::getUri();
-
+        /* If multiple mongoses are allowed, the multi-mongos load balanced URI
+         * can be used if available; otherwise, fall back MONGODB_URI. */
         if ($allowMultipleMongoses) {
-            return $uri;
-        }
-
-        $urlParts = parse_url($uri);
-        if ($urlParts === false) {
-            return $uri;
-        }
-
-        // Only modify URIs using the mongodb scheme
-        if ($urlParts['scheme'] !== 'mongodb') {
-            return $uri;
+            return getenv('MONGODB_MULTI_MONGOS_LB_URI') ?: parent::getUri();
         }
 
-        $hosts = explode(',', $urlParts['host']);
-        $numHosts = count($hosts);
-        if ($numHosts === 1) {
-            return $uri;
-        }
-
-        $manager = static::createTestManager($uri);
-        if ($manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY))->getType() !== Server::TYPE_MONGOS) {
-            return $uri;
-        }
-
-        // Re-append port to last host
-        if (isset($urlParts['port'])) {
-            $hosts[$numHosts - 1] .= ':' . $urlParts['port'];
-        }
-
-        $parts = ['mongodb://'];
-
-        if (isset($urlParts['user'], $urlParts['pass'])) {
-            $parts += [
-                $urlParts['user'],
-                ':',
-                $urlParts['pass'],
-                '@',
-            ];
-        }
-
-        $parts[] = $hosts[0];
-
-        if (isset($urlParts['path'])) {
-            $parts[] = $urlParts['path'];
-        }
-
-        if (isset($urlParts['query'])) {
-            $parts = array_merge($parts, [
-                '?',
-                $urlParts['query'],
-            ]);
-        }
-
-        return implode('', $parts);
+        /* If multiple mongoses are prohibited, the single-mongos load balanced
+         * URI can be used if available; otherwise, we need to conditionally
+         * process MONGODB_URI. */
+        return getenv('MONGODB_SINGLE_MONGOS_LB_URI') ?: static::getUriWithoutMultipleMongoses();
     }
 
     protected function assertCollectionCount($namespace, $count): void
@@ -629,6 +581,70 @@ private function disableFailPoints(): void
         }
     }
 
+    private static function getUriWithoutMultipleMongoses(): string
+    {
+        /* Cache the result. We can safely assume the topology type will remain
+         * constant for the duration of the test suite. */
+        static $uri;
+
+        if (isset($uri)) {
+            return $uri;
+        }
+
+        $uri = parent::getUri();
+        $parsed = parse_url($uri);
+
+        if (! isset($parsed['scheme'], $parsed['host'])) {
+            throw new UnexpectedValueException('Failed to parse scheme and host components from URI: ' . $uri);
+        }
+
+        // Only modify URIs using the mongodb scheme
+        if ($parsed['scheme'] !== 'mongodb') {
+            return $uri;
+        }
+
+        $hosts = explode(',', $parsed['host']);
+        $numHosts = count($hosts);
+
+        if ($numHosts === 1) {
+            return $uri;
+        }
+
+        $manager = static::createTestManager($uri);
+        if ($manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY))->getType() !== Server::TYPE_MONGOS) {
+            return $uri;
+        }
+
+        // Re-append port to last host
+        if (isset($parsed['port'])) {
+            $hosts[$numHosts - 1] .= ':' . $parsed['port'];
+        }
+
+        $parts = ['mongodb://'];
+
+        if (isset($parsed['user'], $parsed['pass'])) {
+            $parts[] = $parsed['user'] . ':' . $parsed['pass'] . '@';
+        }
+
+        $parts[] = $hosts[0];
+
+        if (isset($parsed['path'])) {
+            $parts[] = $parsed['path'];
+        } elseif (isset($parsed['query'])) {
+            /* URIs containing connection options but no auth database component
+             * still require a slash before the question mark */
+            $parts[] = '/';
+        }
+
+        if (isset($parsed['query'])) {
+            $parts[] = '?' . $parsed['query'];
+        }
+
+        $uri = implode('', $parts);
+
+        return $uri;
+    }
+
     /**
      * Checks if the failCommand command is supported on this server version
      */
diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php
index 15f4fefe6..134b0249a 100644
--- a/tests/SpecTests/TransactionsSpecTest.php
+++ b/tests/SpecTests/TransactionsSpecTest.php
@@ -235,7 +235,7 @@ public function testStartingNewTransactionOnPinnedSessionUnpinsSession(): void
             $this->markTestSkipped('Pinning tests require mongos');
         }
 
-        $client = self::createTestClient($this->getUri(true));
+        $client = self::createTestClient(static::getUri(true));
 
         $session = $client->startSession();
         $collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
@@ -275,7 +275,7 @@ public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession()
             $this->markTestSkipped('Pinning tests require mongos');
         }
 
-        $client = self::createTestClient($this->getUri(true));
+        $client = self::createTestClient(static::getUri(true));
 
         $session = $client->startSession();
         $collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php
index 668eec997..ba3e5242b 100644
--- a/tests/UnifiedSpecTests/UnifiedTestRunner.php
+++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php
@@ -543,14 +543,12 @@ private function createContext(): Context
             $context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri);
         }
 
-        /* TODO: Enable this logic once PHPLIB-794 is implemented. For now, load
-         * balancer tests will continue to use MONGODB_URI. */
-        if (false && $this->getPrimaryServer()->getType() === Server::TYPE_LOAD_BALANCER && ! $this->isServerless()) {
+        if ($this->getPrimaryServer()->getType() === Server::TYPE_LOAD_BALANCER && ! $this->isServerless()) {
             $singleMongosUri = getenv('MONGODB_SINGLE_MONGOS_LB_URI');
             $multiMongosUri = getenv('MONGODB_MULTI_MONGOS_LB_URI');
 
-            assertNotFalse($singleMongosUri);
-            assertNotFalse($multiMongosUri);
+            assertNotEmpty($singleMongosUri);
+            assertNotEmpty($multiMongosUri);
 
             $context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri);
         }

From fe3b308b61a944534eeea243187ee5e5f46f8f91 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 11 Jan 2023 09:32:08 +0200
Subject: [PATCH 247/321] Use actions/checkout@v3 (#1029)

It is still used here and there in the CI
---
 .github/workflows/coding-standards.yml | 2 +-
 .github/workflows/static-analysis.yml  | 2 +-
 .github/workflows/tests.yml            | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index 7ce7ca500..b208db098 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -26,7 +26,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: Setup cache environment
         id: extcache
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 52c49a04b..38146dfa3 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -26,7 +26,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: Setup cache environment
         id: extcache
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 319ee5088..000053bdd 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -62,7 +62,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 

From 6d00c48af31d570aadef3a5826fff0f948a318e2 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 11 Jan 2023 09:33:00 +0200
Subject: [PATCH 248/321] Fix typos in method documentation (#1030)

---
 src/BulkWriteResult.php  | 12 ++++++------
 src/DeleteResult.php     |  2 +-
 src/InsertManyResult.php |  2 +-
 src/InsertOneResult.php  |  2 +-
 src/UpdateResult.php     |  8 ++++----
 5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/BulkWriteResult.php b/src/BulkWriteResult.php
index dec8d59de..b73771e03 100644
--- a/src/BulkWriteResult.php
+++ b/src/BulkWriteResult.php
@@ -48,7 +48,7 @@ public function __construct(WriteResult $writeResult, array $insertedIds)
      *
      * @see BulkWriteResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getDeletedCount()
     {
@@ -66,7 +66,7 @@ public function getDeletedCount()
      *
      * @see BulkWriteResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getInsertedCount()
     {
@@ -100,7 +100,7 @@ public function getInsertedIds()
      *
      * @see BulkWriteResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getMatchedCount()
     {
@@ -121,7 +121,7 @@ public function getMatchedCount()
      *
      * @see BulkWriteResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getModifiedCount()
     {
@@ -139,7 +139,7 @@ public function getModifiedCount()
      *
      * @see BulkWriteResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getUpsertedCount()
     {
@@ -162,7 +162,7 @@ public function getUpsertedCount()
      *
      * @see BulkWriteResult::isAcknowledged()
      * @return array
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getUpsertedIds()
     {
diff --git a/src/DeleteResult.php b/src/DeleteResult.php
index 697ee8692..3c5b2cdd4 100644
--- a/src/DeleteResult.php
+++ b/src/DeleteResult.php
@@ -44,7 +44,7 @@ public function __construct(WriteResult $writeResult)
      *
      * @see DeleteResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getDeletedCount()
     {
diff --git a/src/InsertManyResult.php b/src/InsertManyResult.php
index d1aabe558..5de89920e 100644
--- a/src/InsertManyResult.php
+++ b/src/InsertManyResult.php
@@ -48,7 +48,7 @@ public function __construct(WriteResult $writeResult, array $insertedIds)
      *
      * @see InsertManyResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getInsertedCount()
     {
diff --git a/src/InsertOneResult.php b/src/InsertOneResult.php
index 6a74eb900..80eb9cf22 100644
--- a/src/InsertOneResult.php
+++ b/src/InsertOneResult.php
@@ -51,7 +51,7 @@ public function __construct(WriteResult $writeResult, $insertedId)
      *
      * @see InsertOneResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getInsertedCount()
     {
diff --git a/src/UpdateResult.php b/src/UpdateResult.php
index 1fbbab600..8c2284ad5 100644
--- a/src/UpdateResult.php
+++ b/src/UpdateResult.php
@@ -44,7 +44,7 @@ public function __construct(WriteResult $writeResult)
      *
      * @see UpdateResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getMatchedCount()
     {
@@ -65,7 +65,7 @@ public function getMatchedCount()
      *
      * @see UpdateResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getModifiedCount()
     {
@@ -83,7 +83,7 @@ public function getModifiedCount()
      *
      * @see UpdateResult::isAcknowledged()
      * @return integer|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getUpsertedCount()
     {
@@ -107,7 +107,7 @@ public function getUpsertedCount()
      *
      * @see UpdateResult::isAcknowledged()
      * @return mixed|null
-     * @throws BadMethodCallException is the write result is unacknowledged
+     * @throws BadMethodCallException if the write result is unacknowledged
      */
     public function getUpsertedId()
     {

From ff004fa70a2893eaf90f9a240119fb1878762077 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 11 Jan 2023 09:34:04 +0200
Subject: [PATCH 249/321] Remove British English spelling in docs (#1031)

Behavior/behavior is used across the whole docs
---
 docs/tutorial/custom-types.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/tutorial/custom-types.txt b/docs/tutorial/custom-types.txt
index 3c1dd1239..5fa5880f3 100644
--- a/docs/tutorial/custom-types.txt
+++ b/docs/tutorial/custom-types.txt
@@ -14,7 +14,7 @@ The driver serializes PHP variables, including objects, into BSON when it
 communicates to the server, and deserializes BSON back into PHP variables when
 it receives data from the server.
 
-It is possible to influence the behaviour by implementing the
+It is possible to influence the behavior by implementing the
 :php:`MongoDB\\BSON\\Persistable ` interface.
 If a class implements this interface, then upon serialization the
 :php:`bsonSerialize ` method is

From 1d61dbc2112b572319808e738181f2ac2f06fdb9 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Wed, 11 Jan 2023 08:42:11 +0100
Subject: [PATCH 250/321] Remove obsolete files (#1028)

---
 Makefile                                      |  17 ---
 .../replica_sets/replicaset-old.json          |  64 ---------
 .../replica_sets/replicaset-one-node.json     |  24 ----
 .../replica_sets/replicaset.json              |  58 --------
 .../sharded_clusters/cluster.json             |  86 ------------
 .../sharded_clusters/cluster_replset.json     | 126 ------------------
 mongo-orchestration/ssl/ca.pem                |  21 ---
 mongo-orchestration/ssl/client.pem            |  48 -------
 mongo-orchestration/ssl/crl.pem               |  13 --
 mongo-orchestration/ssl/server.pem            |  49 -------
 .../standalone/standalone-auth.json           |  17 ---
 .../standalone/standalone-old.json            |  16 ---
 .../standalone/standalone-ssl.json            |  21 ---
 .../standalone/standalone.json                |  14 --
 14 files changed, 574 deletions(-)
 delete mode 100644 Makefile
 delete mode 100644 mongo-orchestration/replica_sets/replicaset-old.json
 delete mode 100644 mongo-orchestration/replica_sets/replicaset-one-node.json
 delete mode 100644 mongo-orchestration/replica_sets/replicaset.json
 delete mode 100644 mongo-orchestration/sharded_clusters/cluster.json
 delete mode 100644 mongo-orchestration/sharded_clusters/cluster_replset.json
 delete mode 100644 mongo-orchestration/ssl/ca.pem
 delete mode 100644 mongo-orchestration/ssl/client.pem
 delete mode 100644 mongo-orchestration/ssl/crl.pem
 delete mode 100644 mongo-orchestration/ssl/server.pem
 delete mode 100644 mongo-orchestration/standalone/standalone-auth.json
 delete mode 100644 mongo-orchestration/standalone/standalone-old.json
 delete mode 100644 mongo-orchestration/standalone/standalone-ssl.json
 delete mode 100644 mongo-orchestration/standalone/standalone.json

diff --git a/Makefile b/Makefile
deleted file mode 100644
index a1d31b68f..000000000
--- a/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-.PHONY: composer test
-
-COMPOSER_ARGS=update --no-interaction --prefer-source
-
-composer:
-	@command -v composer >/dev/null 2>&1; \
-	if test $$? -eq 0; then \
-		composer $(COMPOSER_ARGS); \
-	elif test -r composer.phar; then \
-		php composer.phar $(COMPOSER_ARGS); \
-	else \
-		echo >&2 "Cannot find composer; aborting."; \
-		false; \
-	fi
-
-test: composer
-	vendor/bin/phpunit
diff --git a/mongo-orchestration/replica_sets/replicaset-old.json b/mongo-orchestration/replica_sets/replicaset-old.json
deleted file mode 100644
index 87c81637c..000000000
--- a/mongo-orchestration/replica_sets/replicaset-old.json
+++ /dev/null
@@ -1,64 +0,0 @@
-{
-    "id": "REPLICASET_OLD",
-    "name": "mongod",
-    "members": [
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3500/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3500/mongod.log",
-                "journal": true,
-                "nssize": 1,
-                "port": 3500,
-                "bind_ip": "::,0.0.0.0",
-                "smallfiles": true
-            },
-            "rsParams": {
-                "tags": {
-                    "ordinal": "one",
-                    "dc": "pa"
-                }
-            },
-            "server_id": "RS-OLD-one"
-        },
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3501/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3501/mongod.log",
-                "journal": true,
-                "nssize": 1,
-                "port": 3501,
-                "bind_ip": "::,0.0.0.0",
-                "smallfiles": true
-            },
-            "rsParams": {
-                "tags": {
-                    "ordinal": "two",
-                    "dc": "nyc"
-                }
-            },
-            "server_id": "RS-OLD-two"
-        },
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3502/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3502/mongod.log",
-                "journal": true,
-                "nssize": 1,
-                "port": 3502,
-                "bind_ip": "::,0.0.0.0",
-                "smallfiles": true
-            },
-            "rsParams": {
-                "arbiterOnly": true
-
-            },
-            "server_id": "RS-OLD-arbiter"
-        }
-    ]
-}
diff --git a/mongo-orchestration/replica_sets/replicaset-one-node.json b/mongo-orchestration/replica_sets/replicaset-one-node.json
deleted file mode 100644
index 8b5bbd045..000000000
--- a/mongo-orchestration/replica_sets/replicaset-one-node.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-    "id": "REPLICASET_SINGLE",
-    "name": "mongod",
-    "members": [
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3020/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3020/mongod.log",
-                "journal": true,
-                "port": 3020,
-                "bind_ip_all": true
-            },
-            "rsParams": {
-                "tags": {
-                    "ordinal": "one",
-                    "dc": "pa"
-                }
-            },
-            "server_id": "RS-alone"
-        }
-    ]
-}
diff --git a/mongo-orchestration/replica_sets/replicaset.json b/mongo-orchestration/replica_sets/replicaset.json
deleted file mode 100644
index a80de8bbb..000000000
--- a/mongo-orchestration/replica_sets/replicaset.json
+++ /dev/null
@@ -1,58 +0,0 @@
-{
-    "id": "REPLICASET",
-    "name": "mongod",
-    "members": [
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3000/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3000/mongod.log",
-                "journal": true,
-                "port": 3000,
-                "bind_ip_all": true
-            },
-            "rsParams": {
-                "tags": {
-                    "ordinal": "one",
-                    "dc": "pa"
-                }
-            },
-            "server_id": "RS-one"
-        },
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3001/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3001/mongod.log",
-                "journal": true,
-                "port": 3001,
-                "bind_ip_all": true
-            },
-            "rsParams": {
-                "tags": {
-                    "ordinal": "two",
-                    "dc": "nyc"
-                }
-            },
-            "server_id": "RS-two"
-        },
-        {
-            "procParams": {
-                "dbpath": "/tmp/REPLICASET/3002/",
-                "ipv6": true,
-                "logappend": true,
-                "logpath": "/tmp/REPLICASET/3002/mongod.log",
-                "journal": true,
-                "port": 3002,
-                "bind_ip_all": true
-            },
-            "rsParams": {
-                "arbiterOnly": true
-
-            },
-            "server_id": "RS-arbiter"
-        }
-    ]
-}
diff --git a/mongo-orchestration/sharded_clusters/cluster.json b/mongo-orchestration/sharded_clusters/cluster.json
deleted file mode 100644
index 094785a7e..000000000
--- a/mongo-orchestration/sharded_clusters/cluster.json
+++ /dev/null
@@ -1,86 +0,0 @@
-{
-    "configsvrs": [ {
-        "members" : [
-            {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED/CFG/4000",
-                    "logpath": "/tmp/SHARDED/CFG/4000/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4000,
-                    "bind_ip_all": true
-                }
-            },
-            {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED/CFG/4001",
-                    "logpath": "/tmp/SHARDED/CFG/4001/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4001,
-                    "bind_ip_all": true
-                }
-            },
-            {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED/CFG/4002",
-                    "logpath": "/tmp/SHARDED/CFG/4002/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4002,
-                    "bind_ip_all": true
-                }
-            }
-        ]
-    } ],
-    "id": "cluster_1", 
-    "shards": [
-        {
-            "id": "sh01", 
-            "shardParams": {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED/SHARD1/4100",
-                    "logpath": "/tmp/SHARDED/SHARD1/4100/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4100,
-                    "bind_ip_all": true
-                }
-            }
-        }, 
-        {
-            "id": "sh02", 
-            "shardParams": {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED/SHARD2/4200",
-                    "logpath": "/tmp/SHARDED/SHARD2/4200/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4200,
-                    "bind_ip_all": true
-                }
-            }
-        }
-    ], 
-    "routers": [
-        {
-            "logpath": "/tmp/SHARDED/ROUTER/4300/mongod.log",
-            "ipv6": true,
-            "logappend": true,
-            "port": 4300,
-            "bind_ip_all": true
-        },
-        {
-            "logpath": "/tmp/SHARDED/ROUTER/4301/mongod.log",
-            "ipv6": true,
-            "logappend": true,
-            "port": 4301,
-            "bind_ip_all": true
-        }
-    ]
-}
diff --git a/mongo-orchestration/sharded_clusters/cluster_replset.json b/mongo-orchestration/sharded_clusters/cluster_replset.json
deleted file mode 100644
index 80cd4c2bd..000000000
--- a/mongo-orchestration/sharded_clusters/cluster_replset.json
+++ /dev/null
@@ -1,126 +0,0 @@
-{
-    "configsvrs": [ {
-        "members" : [
-            {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED-RS/CFG/4490",
-                    "logpath": "/tmp/SHARDED-RS/CFG/4490/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4490,
-                    "bind_ip_all": true
-                }
-            },
-            {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED-RS/CFG/4491",
-                    "logpath": "/tmp/SHARDED-RS/CFG/4491/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4491,
-                    "bind_ip_all": true
-                }
-            },
-            {
-                "procParams": {
-                    "dbpath": "/tmp/SHARDED-RS/CFG/4492",
-                    "logpath": "/tmp/SHARDED-RS/CFG/4492/mongod.log",
-                    "ipv6": true,
-                    "journal": true,
-                    "logappend": true,
-                    "port": 4492,
-                    "bind_ip_all": true
-                }
-            }
-        ]
-    } ],
-    "id": "cluster_rs",
-    "shards": [
-        {
-            "id": "cluster-rs-sh01", 
-            "shardParams": {
-                "id": "sh01-rs",
-                "members": [
-                    { "procParams": {
-                        "dbpath": "/tmp/SHARDED-RS/SHARD1/4400",
-                        "logpath": "/tmp/SHARDED-RS/SHARD1/4400/mongod.log",
-                        "ipv6": true,
-                        "journal": true,
-                        "logappend": true,
-                        "port": 4400,
-                        "bind_ip_all": true,
-                        "setParameter":  {
-                            "periodicNoopIntervalSecs":  1,
-                            "writePeriodicNoops":  true
-                        }
-                    } },
-                    { "procParams": {
-                        "dbpath": "/tmp/SHARDED-RS/SHARD1/4401",
-                        "logpath": "/tmp/SHARDED-RS/SHARD1/4401/mongod.log",
-                        "ipv6": true,
-                        "journal": true,
-                        "logappend": true,
-                        "port": 4401,
-                        "bind_ip_all": true,
-                        "setParameter":  {
-                            "periodicNoopIntervalSecs":  1,
-                            "writePeriodicNoops":  true
-                        }
-                    } }
-                ]
-            }
-        }, 
-        {
-            "id": "cluster-rs-sh02", 
-            "shardParams": {
-                "id": "sh02-rs",
-                "members": [
-                    { "procParams": {
-                        "dbpath": "/tmp/SHARDED-RS/SHARD2/4410",
-                        "logpath": "/tmp/SHARDED-RS/SHARD2/4410/mongod.log",
-                        "ipv6": true,
-                        "journal": true,
-                        "logappend": true,
-                        "port": 4410,
-                        "bind_ip_all": true,
-                        "setParameter":  {
-                            "periodicNoopIntervalSecs":  1,
-                            "writePeriodicNoops":  true
-                        }
-                    } },
-                    { "procParams": {
-                        "dbpath": "/tmp/SHARDED-RS/SHARD2/4411",
-                        "logpath": "/tmp/SHARDED-RS/SHARD2/4411/mongod.log",
-                        "ipv6": true,
-                        "journal": true,
-                        "logappend": true,
-                        "port": 4411,
-                        "bind_ip_all": true,
-                        "setParameter":  {
-                            "periodicNoopIntervalSecs":  1,
-                            "writePeriodicNoops":  true
-                        }
-                    } }
-                ]
-            }
-        }
-    ], 
-    "routers": [
-        {
-            "logpath": "/tmp/SHARDED-RS/ROUTER/4430/mongod.log",
-            "ipv6": true,
-            "logappend": true,
-            "port": 4430,
-            "bind_ip_all": true
-        },
-        {
-            "logpath": "/tmp/SHARDED-RS/ROUTER/4431/mongod.log",
-            "ipv6": true,
-            "logappend": true,
-            "port": 4431,
-            "bind_ip_all": true
-        }
-    ]
-}
diff --git a/mongo-orchestration/ssl/ca.pem b/mongo-orchestration/ssl/ca.pem
deleted file mode 100644
index 6ac86cfcc..000000000
--- a/mongo-orchestration/ssl/ca.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDfzCCAmegAwIBAgIDB1MGMA0GCSqGSIb3DQEBCwUAMHkxGzAZBgNVBAMTEkRy
-aXZlcnMgVGVzdGluZyBDQTEQMA4GA1UECxMHRHJpdmVyczEQMA4GA1UEChMHTW9u
-Z29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsx
-CzAJBgNVBAYTAlVTMB4XDTE5MDUyMjIwMjMxMVoXDTM5MDUyMjIwMjMxMVoweTEb
-MBkGA1UEAxMSRHJpdmVycyBUZXN0aW5nIENBMRAwDgYDVQQLEwdEcml2ZXJzMRAw
-DgYDVQQKEwdNb25nb0RCMRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQI
-EwhOZXcgWW9yazELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQCl7VN+WsQfHlwapcOpTLZVoeMAl1LTbWTFuXSAavIyy0W1Ytky1UP/
-bxCSW0mSWwCgqoJ5aXbAvrNRp6ArWu3LsTQIEcD3pEdrFIVQhYzWUs9fXqPyI9k+
-QNNQ+MRFKeGteTPYwF2eVEtPzUHU5ws3+OKp1m6MCLkwAG3RBFUAfddUnLvGoZiT
-pd8/eNabhgHvdrCw+tYFCWvSjz7SluEVievpQehrSEPKe8DxJq/IM3tSl3tdylzT
-zeiKNO7c7LuQrgjAfrZl7n2SriHIlNmqiDR/kdd8+TxBuxjFlcf2WyHCO3lIcIgH
-KXTlhUCg50KfHaxHu05Qw0x8869yIzqbAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8w
-DQYJKoZIhvcNAQELBQADggEBAEHuhTL8KQZcKCTSJbYA9MgZj7U32arMGBbc1hiq
-VBREwvdVz4+9tIyWMzN9R/YCKmUTnCq8z3wTlC8kBtxYn/l4Tj8nJYcgLJjQ0Fwe
-gT564CmvkUat8uXPz6olOCdwkMpJ9Sj62i0mpgXJdBfxKQ6TZ9yGz6m3jannjZpN
-LchB7xSAEWtqUgvNusq0dApJsf4n7jZ+oBZVaQw2+tzaMfaLqHgMwcu1FzA8UKCD
-sxCgIsZUs8DdxaD418Ot6nPfheOTqe24n+TTa+Z6O0W0QtnofJBx7tmAo1aEc57i
-77s89pfwIJetpIlhzNSMKurCAocFCJMJLAASJFuu6dyDvPo=
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/mongo-orchestration/ssl/client.pem b/mongo-orchestration/ssl/client.pem
deleted file mode 100644
index 5b0700109..000000000
--- a/mongo-orchestration/ssl/client.pem
+++ /dev/null
@@ -1,48 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAsNS8UEuin7/K29jXfIOLpIoh1jEyWVqxiie2Onx7uJJKcoKo
-khA3XeUnVN0k6X5MwYWcN52xcns7LYtyt06nRpTG2/emoV44w9uKTuHsvUbiOwSV
-m/ToKQQ4FUFZoqorXH+ZmJuIpJNfoW+3CkE1vEDCIecIq6BNg5ySsPtvSuSJHGjp
-mc7/5ZUDvFE2aJ8QbJU3Ws0HXiEb6ymi048LlzEL2VKX3w6mqqh+7dcZGAy7qYk2
-5FZ9ktKvCeQau7mTyU1hsPrKFiKtMN8Q2ZAItX13asw5/IeSTq2LgLFHlbj5Kpq4
-GmLdNCshzH5X7Ew3IYM8EHmsX8dmD6mhv7vpVwIDAQABAoIBABOdpb4qhcG+3twA
-c/cGCKmaASLnljQ/UU6IFTjrsjXJVKTbRaPeVKX/05sgZQXZ0t3s2mV5AsQ2U1w8
-Cd+3w+qaemzQThW8hAOGCROzEDX29QWi/o2sX0ydgTMqaq0Wv3SlWv6I0mGfT45y
-/BURIsrdTCvCmz2erLqa1dL4MWJXRFjT9UTs5twlecIOM2IHKoGGagFhymRK4kDe
-wTRC9fpfoAgyfus3pCO/wi/F8yKGPDEwY+zgkhrJQ+kSeki7oKdGD1H540vB8gRt
-EIqssE0Y6rEYf97WssQlxJgvoJBDSftOijS6mwvoasDUwfFqyyPiirawXWWhHXkc
-DjIi/XECgYEA5xfjilw9YyM2UGQNESbNNunPcj7gDZbN347xJwmYmi9AUdPLt9xN
-3XaMqqR22k1DUOxC/5hH0uiXir7mDfqmC+XS/ic/VOsa3CDWejkEnyGLiwSHY502
-wD/xWgHwUiGVAG9HY64vnDGm6L3KGXA2oqxanL4V0+0+Ht49pZ16i8sCgYEAw+Ox
-CHGtpkzjCP/z8xr+1VTSdpc/4CP2HONnYopcn48KfQnf7Nale69/1kZpypJlvQSG
-eeA3jMGigNJEkb8/kaVoRLCisXcwLc0XIfCTeiK6FS0Ka30D/84Qm8UsHxRdpGkM
-kYITAa2r64tgRL8as4/ukeXBKE+oOhX43LeEfyUCgYBkf7IX2Ndlhsm3GlvIarxy
-NipeP9PGdR/hKlPbq0OvQf9R1q7QrcE7H7Q6/b0mYNV2mtjkOQB7S2WkFDMOP0P5
-BqDEoKLdNkV/F9TOYH+PCNKbyYNrodJOt0Ap6Y/u1+Xpw3sjcXwJDFrO+sKqX2+T
-PStG4S+y84jBedsLbDoAEwKBgQCTz7/KC11o2yOFqv09N+WKvBKDgeWlD/2qFr3w
-UU9K5viXGVhqshz0k5z25vL09Drowf1nAZVpFMO2SPOMtq8VC6b+Dfr1xmYIaXVH
-Gu1tf77CM9Zk/VSDNc66e7GrUgbHBK2DLo+A+Ld9aRIfTcSsMbNnS+LQtCrQibvb
-cG7+MQKBgQCY11oMT2dUekoZEyW4no7W5D74lR8ztMjp/fWWTDo/AZGPBY6cZoZF
-IICrzYtDT/5BzB0Jh1f4O9ZQkm5+OvlFbmoZoSbMzHL3oJCBOY5K0/kdGXL46WWh
-IRJSYakNU6VIS7SjDpKgm9D8befQqZeoSggSjIIULIiAtYgS80vmGA==
------END RSA PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-MIIDgzCCAmugAwIBAgIDAxOUMA0GCSqGSIb3DQEBCwUAMHkxGzAZBgNVBAMTEkRy
-aXZlcnMgVGVzdGluZyBDQTEQMA4GA1UECxMHRHJpdmVyczEQMA4GA1UEChMHTW9u
-Z29EQjEWMBQGA1UEBxMNTmV3IFlvcmsgQ2l0eTERMA8GA1UECBMITmV3IFlvcmsx
-CzAJBgNVBAYTAlVTMB4XDTE5MDUyMjIzNTU1NFoXDTM5MDUyMjIzNTU1NFowaTEP
-MA0GA1UEAxMGY2xpZW50MRAwDgYDVQQLEwdEcml2ZXJzMQwwCgYDVQQKEwNNREIx
-FjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYD
-VQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALDUvFBLop+/
-ytvY13yDi6SKIdYxMllasYontjp8e7iSSnKCqJIQN13lJ1TdJOl+TMGFnDedsXJ7
-Oy2LcrdOp0aUxtv3pqFeOMPbik7h7L1G4jsElZv06CkEOBVBWaKqK1x/mZibiKST
-X6FvtwpBNbxAwiHnCKugTYOckrD7b0rkiRxo6ZnO/+WVA7xRNmifEGyVN1rNB14h
-G+spotOPC5cxC9lSl98Opqqofu3XGRgMu6mJNuRWfZLSrwnkGru5k8lNYbD6yhYi
-rTDfENmQCLV9d2rMOfyHkk6ti4CxR5W4+SqauBpi3TQrIcx+V+xMNyGDPBB5rF/H
-Zg+pob+76VcCAwEAAaMkMCIwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUF
-BwMCMA0GCSqGSIb3DQEBCwUAA4IBAQAqRcLAGvYMaGYOV4HJTzNotT2qE0I9THNQ
-wOV1fBg69x6SrUQTQLjJEptpOA288Wue6Jt3H+p5qAGV5GbXjzN/yjCoItggSKxG
-Xg7279nz6/C5faoIKRjpS9R+MsJGlttP9nUzdSxrHvvqm62OuSVFjjETxD39DupE
-YPFQoHOxdFTtBQlc/zIKxVdd20rs1xJeeU2/L7jtRBSPuR/Sk8zot7G2/dQHX49y
-kHrq8qz12kj1T6XDXf8KZawFywXaz0/Ur+fUYKmkVk1T0JZaNtF4sKqDeNE4zcns
-p3xLVDSl1Q5Gwj7bgph9o4Hxs9izPwiqjmNaSjPimGYZ399zcurY
------END CERTIFICATE-----
diff --git a/mongo-orchestration/ssl/crl.pem b/mongo-orchestration/ssl/crl.pem
deleted file mode 100644
index 733a0acdc..000000000
--- a/mongo-orchestration/ssl/crl.pem
+++ /dev/null
@@ -1,13 +0,0 @@
------BEGIN X509 CRL-----
-MIIB6jCB0wIBATANBgkqhkiG9w0BAQsFADB5MRswGQYDVQQDExJEcml2ZXJzIFRl
-c3RpbmcgQ0ExEDAOBgNVBAsTB0RyaXZlcnMxEDAOBgNVBAoTB01vbmdvREIxFjAU
-BgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQG
-EwJVUxcNMTkwNTIyMjI0NTUzWhcNMTkwNjIxMjI0NTUzWjAVMBMCAncVFw0xOTA1
-MjIyMjQ1MzJaoA8wDTALBgNVHRQEBAICEAAwDQYJKoZIhvcNAQELBQADggEBACwQ
-W9OF6ExJSzzYbpCRroznkfdLG7ghNSxIpBQUGtcnYbkP4em6TdtAj5K3yBjcKn4a
-hnUoa5EJGr2Xgg0QascV/1GuWEJC9rsYYB9boVi95l1CrkS0pseaunM086iItZ4a
-hRVza8qEMBc3rdsracA7hElYMKdFTRLpIGciJehXzv40yT5XFBHGy/HIT0CD50O7
-BDOHzA+rCFCvxX8UY9myDfb1r1zUW7Gzjn241VT7bcIJmhFE9oV0popzDyqr6GvP
-qB2t5VmFpbnSwkuc4ie8Jizip1P8Hg73lut3oVAHACFGPpfaNIAp4GcSH61zJmff
-9UBe3CJ1INwqyiuqGeA=
------END X509 CRL-----
diff --git a/mongo-orchestration/ssl/server.pem b/mongo-orchestration/ssl/server.pem
deleted file mode 100644
index 7480f9644..000000000
--- a/mongo-orchestration/ssl/server.pem
+++ /dev/null
@@ -1,49 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAhNrB0E6GY/kFSd8/vNpu/t952tbnOsD5drV0XPvmuy7SgKDY
-a/S+xb/jPnlZKKehdBnH7qP/gYbv34ZykzcDFZscjPLiGc2cRGP+NQCSFK0d2/7d
-y15zSD3zhj14G8+MkpAejTU+0/qFNZMc5neDvGanTe0+8aWa0DXssM0MuTxIv7j6
-CtsMWeqLLofN7a1Kw2UvmieCHfHMuA/08pJwRnV/+5T9WONBPJja2ZQRrG1BjpI4
-81zSPUZesIqi8yDlExdvgNaRZIEHi/njREqwVgJOZomUY57zmKypiMzbz48dDTsV
-gUStxrEqbaP+BEjQYPX5+QQk4GdMjkLf52LR6QIDAQABAoIBAHSs+hHLJNOf2zkp
-S3y8CUblVMsQeTpsR6otaehPgi9Zy50TpX4KD5D0GMrBH8BIl86y5Zd7h+VlcDzK
-gs0vPxI2izhuBovKuzaE6rf5rFFkSBjxGDCG3o/PeJOoYFdsS3RcBbjVzju0hFCs
-xnDQ/Wz0anJRrTnjyraY5SnQqx/xuhLXkj/lwWoWjP2bUqDprnuLOj16soNu60Um
-JziWbmWx9ty0wohkI/8DPBl9FjSniEEUi9pnZXPElFN6kwPkgdfT5rY/TkMH4lsu
-ozOUc5xgwlkT6kVjXHcs3fleuT/mOfVXLPgNms85JKLucfd6KiV7jYZkT/bXIjQ+
-7CZEn0ECgYEA5QiKZgsfJjWvZpt21V/i7dPje2xdwHtZ8F9NjX7ZUFA7mUPxUlwe
-GiXxmy6RGzNdnLOto4SF0/7ebuF3koO77oLup5a2etL+y/AnNAufbu4S5D72sbiz
-wdLzr3d5JQ12xeaEH6kQNk2SD5/ShctdS6GmTgQPiJIgH0MIdi9F3v0CgYEAlH84
-hMWcC+5b4hHUEexeNkT8kCXwHVcUjGRaYFdSHgovvWllApZDHSWZ+vRcMBdlhNPu
-09Btxo99cjOZwGYJyt20QQLGc/ZyiOF4ximQzabTeFgLkTH3Ox6Mh2Rx9yIruYoX
-nE3UfMDkYELanEJUv0zenKpZHw7tTt5yXXSlEF0CgYBSsEOvVcKYO/eoluZPYQAA
-F2jgzZ4HeUFebDoGpM52lZD+463Dq2hezmYtPaG77U6V3bUJ/TWH9VN/Or290vvN
-v83ECcC2FWlSXdD5lFyqYx/E8gqE3YdgqfW62uqM+xBvoKsA9zvYLydVpsEN9v8m
-6CSvs/2btA4O21e5u5WBTQKBgGtAb6vFpe0gHRDs24SOeYUs0lWycPhf+qFjobrP
-lqnHpa9iPeheat7UV6BfeW3qmBIVl/s4IPE2ld4z0qqZiB0Tf6ssu/TpXNPsNXS6
-dLFz+myC+ufFdNEoQUtQitd5wKbjTCZCOGRaVRgJcSdG6Tq55Fa22mOKPm+mTmed
-ZdKpAoGAFsTYBAHPxs8nzkCJCl7KLa4/zgbgywO6EcQgA7tfelB8bc8vcAMG5o+8
-YqAfwxrzhVSVbJx0fibTARXROmbh2pn010l2wj3+qUajM8NiskCPFbSjGy7HSUze
-P8Kt1uMDJdj55gATzn44au31QBioZY2zXleorxF21cr+BZCJgfA=
------END RSA PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-MIIDlTCCAn2gAwIBAgICdxUwDQYJKoZIhvcNAQELBQAweTEbMBkGA1UEAxMSRHJp
-dmVycyBUZXN0aW5nIENBMRAwDgYDVQQLEwdEcml2ZXJzMRAwDgYDVQQKEwdNb25n
-b0RCMRYwFAYDVQQHEw1OZXcgWW9yayBDaXR5MREwDwYDVQQIEwhOZXcgWW9yazEL
-MAkGA1UEBhMCVVMwHhcNMTkwNTIyMjIzMjU2WhcNMzkwNTIyMjIzMjU2WjBwMRIw
-EAYDVQQDEwlsb2NhbGhvc3QxEDAOBgNVBAsTB0RyaXZlcnMxEDAOBgNVBAoTB01v
-bmdvREIxFjAUBgNVBAcTDU5ldyBZb3JrIENpdHkxETAPBgNVBAgTCE5ldyBZb3Jr
-MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAITa
-wdBOhmP5BUnfP7zabv7fedrW5zrA+Xa1dFz75rsu0oCg2Gv0vsW/4z55WSinoXQZ
-x+6j/4GG79+GcpM3AxWbHIzy4hnNnERj/jUAkhStHdv+3ctec0g984Y9eBvPjJKQ
-Ho01PtP6hTWTHOZ3g7xmp03tPvGlmtA17LDNDLk8SL+4+grbDFnqiy6Hze2tSsNl
-L5ongh3xzLgP9PKScEZ1f/uU/VjjQTyY2tmUEaxtQY6SOPNc0j1GXrCKovMg5RMX
-b4DWkWSBB4v540RKsFYCTmaJlGOe85isqYjM28+PHQ07FYFErcaxKm2j/gRI0GD1
-+fkEJOBnTI5C3+di0ekCAwEAAaMwMC4wLAYDVR0RBCUwI4IJbG9jYWxob3N0hwR/
-AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUAA4IBAQBol8+YH7MA
-HwnIh7KcJ8h87GkCWsjOJCDJWiYBJArQ0MmgDO0qdx+QEtvLMn3XNtP05ZfK0WyX
-or4cWllAkMFYaFbyB2hYazlD1UAAG+22Rku0UP6pJMLbWe6pnqzx+RL68FYdbZhN
-fCW2xiiKsdPoo2VEY7eeZKrNr/0RFE5EKXgzmobpTBQT1Dl3Ve4aWLoTy9INlQ/g
-z40qS7oq1PjjPLgxINhf4ncJqfmRXugYTOnyFiVXLZTys5Pb9SMKdToGl3NTYWLL
-2AZdjr6bKtT+WtXyHqO0cQ8CkAW0M6VOlMluACllcJxfrtdlQS2S4lUIj76QKBdZ
-khBHXq/b8MFX
------END CERTIFICATE-----
diff --git a/mongo-orchestration/standalone/standalone-auth.json b/mongo-orchestration/standalone/standalone-auth.json
deleted file mode 100644
index b15a68566..000000000
--- a/mongo-orchestration/standalone/standalone-auth.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "name": "mongod",
-    "id" : "STANDALONE_AUTH",
-    "auth_key": "secret",
-    "login": "root",
-    "password": "toor",
-    "procParams": {
-        "dbpath": "/tmp/standalone-auth/",
-        "ipv6": true,
-        "logappend": true,
-        "logpath": "/tmp/standalone-auth/m.log",
-        "journal": true,
-        "port": 2200,
-        "bind_ip_all": true,
-        "setParameter": {"enableTestCommands": 1}
-    }
-}
diff --git a/mongo-orchestration/standalone/standalone-old.json b/mongo-orchestration/standalone/standalone-old.json
deleted file mode 100644
index e89f013b8..000000000
--- a/mongo-orchestration/standalone/standalone-old.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-    "name": "mongod",
-    "id" : "STANDALONE",
-    "procParams": {
-        "dbpath": "/tmp/standalone/",
-        "ipv6": true,
-        "logappend": true,
-        "logpath": "/tmp/standalone/mongod.log",
-        "journal": true,
-        "nssize": 1,
-        "port": 2700,
-        "bind_ip": "::,0.0.0.0",
-        "smallfiles": true,
-        "setParameter": {"enableTestCommands": 1}
-    }
-}
diff --git a/mongo-orchestration/standalone/standalone-ssl.json b/mongo-orchestration/standalone/standalone-ssl.json
deleted file mode 100644
index f843589e6..000000000
--- a/mongo-orchestration/standalone/standalone-ssl.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-    "name": "mongod",
-    "id" : "STANDALONE_SSL",
-    "procParams": {
-        "dbpath": "/tmp/standalone-ssl/",
-        "ipv6": true,
-        "logappend": true,
-        "logpath": "/tmp/standalone-ssl/m.log",
-        "journal": true,
-        "port": 2100,
-        "bind_ip_all": true,
-        "setParameter": {"enableTestCommands": 1}
-    },
-    "sslParams": {
-        "sslMode": "requireSSL",
-        "sslCAFile": "$TRAVIS_BUILD_DIR/mongo-orchestration/ssl/ca.pem",
-        "sslPEMKeyFile": "$TRAVIS_BUILD_DIR/mongo-orchestration/ssl/server.pem",
-        "sslWeakCertificateValidation": true,
-        "sslAllowInvalidHostnames": true
-    }
-}
diff --git a/mongo-orchestration/standalone/standalone.json b/mongo-orchestration/standalone/standalone.json
deleted file mode 100644
index 4cb451114..000000000
--- a/mongo-orchestration/standalone/standalone.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "name": "mongod",
-    "id" : "STANDALONE",
-    "procParams": {
-        "dbpath": "/tmp/standalone/",
-        "ipv6": true,
-        "logappend": true,
-        "logpath": "/tmp/standalone/mongod.log",
-        "journal": true,
-        "port": 2000,
-        "bind_ip_all": true,
-        "setParameter": {"enableTestCommands": 1}
-    }
-}

From 7bcc7f434f290879f618fa26ffbb5753c70c8bbc Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Thu, 12 Jan 2023 08:32:07 +0100
Subject: [PATCH 251/321] Use `actions/cache@v3` (#1033)

Based on https://github.com/actions/cache/blob/main/RELEASES.md I cannot find any BC breaks
---
 .github/workflows/coding-standards.yml | 2 +-
 .github/workflows/static-analysis.yml  | 2 +-
 .github/workflows/tests.yml            | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index b208db098..d4cbe7dee 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -37,7 +37,7 @@ jobs:
           key: "extcache-v1"
 
       - name: Cache extensions
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: ${{ steps.extcache.outputs.dir }}
           key: ${{ steps.extcache.outputs.key }}
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 38146dfa3..7e1aaa76e 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -37,7 +37,7 @@ jobs:
           key: "extcache-v1"
 
       - name: Cache extensions
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: ${{ steps.extcache.outputs.dir }}
           key: ${{ steps.extcache.outputs.key }}
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 000053bdd..70e131df7 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -81,7 +81,7 @@ jobs:
           key: "extcache-v1"
 
       - name: Cache extensions
-        uses: actions/cache@v2
+        uses: actions/cache@v3
         with:
           path: ${{ steps.extcache.outputs.dir }}
           key: ${{ steps.extcache.outputs.key }}

From fd37f1b3a63e9a273959341071998b9fff5d40e2 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Thu, 12 Jan 2023 09:06:31 +0100
Subject: [PATCH 252/321] Drop support for `jean85/pretty-package-versions` 1
 (#1027)

---
 composer.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/composer.json b/composer.json
index f26bb053b..1ddd6783d 100644
--- a/composer.json
+++ b/composer.json
@@ -13,7 +13,7 @@
         "ext-hash": "*",
         "ext-json": "*",
         "ext-mongodb": "^1.16.0",
-        "jean85/pretty-package-versions": "^1.2 || ^2.0.1",
+        "jean85/pretty-package-versions": "^2.0.1",
         "symfony/polyfill-php80": "^1.19"
     },
     "require-dev": {

From f236312d4b4770ae4f5c81a270e9178f1ecb9b26 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Mon, 16 Jan 2023 08:53:59 +0100
Subject: [PATCH 253/321] PHPLIB-935: Propagate Original Error for Write Errors
 Labeled NoWritesPerformed (#1034)

---
 tests/SpecTests/RetryableWritesSpecTest.php | 91 +++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/tests/SpecTests/RetryableWritesSpecTest.php b/tests/SpecTests/RetryableWritesSpecTest.php
index bdbb3b293..4479d9806 100644
--- a/tests/SpecTests/RetryableWritesSpecTest.php
+++ b/tests/SpecTests/RetryableWritesSpecTest.php
@@ -2,11 +2,17 @@
 
 namespace MongoDB\Tests\SpecTests;
 
+use MongoDB\Driver\Exception\BulkWriteException;
+use MongoDB\Driver\Monitoring\CommandFailedEvent;
+use MongoDB\Driver\Monitoring\CommandStartedEvent;
+use MongoDB\Driver\Monitoring\CommandSubscriber;
+use MongoDB\Driver\Monitoring\CommandSucceededEvent;
 use stdClass;
 
 use function basename;
 use function file_get_contents;
 use function glob;
+use function version_compare;
 
 /**
  * Retryable writes spec tests.
@@ -16,6 +22,9 @@
  */
 class RetryableWritesSpecTest extends FunctionalTestCase
 {
+    public const NOT_PRIMARY = 10107;
+    public const SHUTDOWN_IN_PROGRESS = 91;
+
     /**
      * Execute an individual test case from the specification.
      *
@@ -71,4 +80,86 @@ public function provideTests()
 
         return $testArgs;
     }
+
+    /**
+     * Prose test 1: when encountering a NoWritesPerformed error after an error with a RetryableWriteError label
+     */
+    public function testNoWritesPerformedErrorReturnsOriginalError(): void
+    {
+        if (! $this->isReplicaSet()) {
+            $this->markTestSkipped('Test only applies to replica sets');
+        }
+
+        if (version_compare($this->getServerVersion(), '4.4.0', '<')) {
+            $this->markTestSkipped('NoWritesPerformed error label is only supported on MongoDB 4.4+');
+        }
+
+        $client = self::createTestClient(null, ['retryWrites' => true]);
+
+        // Step 2: Configure a fail point with error code 91
+        $this->configureFailPoint([
+            'configureFailPoint' => 'failCommand',
+            'mode' => ['times' => 1],
+            'data' => [
+                'writeConcernError' => [
+                    'code' => self::SHUTDOWN_IN_PROGRESS,
+                    'errorLabels' => ['RetryableWriteError'],
+                ],
+                'failCommands' => ['insert'],
+            ],
+        ]);
+
+        $subscriber = new class ($this) implements CommandSubscriber {
+            private $testCase;
+
+            public function __construct(FunctionalTestCase $testCase)
+            {
+                $this->testCase = $testCase;
+            }
+
+            public function commandStarted(CommandStartedEvent $event): void
+            {
+            }
+
+            public function commandSucceeded(CommandSucceededEvent $event): void
+            {
+                if ($event->getCommandName() === 'insert') {
+                    // Step 3: Configure a fail point with code 10107
+                    $this->testCase->configureFailPoint([
+                        'configureFailPoint' => 'failCommand',
+                        'mode' => ['times' => 1],
+                        'data' => [
+                            'errorCode' => RetryableWritesSpecTest::NOT_PRIMARY,
+                            'errorLabels' => ['RetryableWriteError', 'NoWritesPerformed'],
+                            'failCommands' => ['insert'],
+                        ],
+                    ]);
+                }
+            }
+
+            public function commandFailed(CommandFailedEvent $event): void
+            {
+            }
+        };
+
+        $client->getManager()->addSubscriber($subscriber);
+
+        // Step 4: Run insertOne
+        try {
+            $client->selectCollection('db', 'retryable_writes')->insertOne(['write' => 1]);
+        } catch (BulkWriteException $e) {
+            $writeConcernError = $e->getWriteResult()->getWriteConcernError();
+            $this->assertNotNull($writeConcernError);
+
+            // Assert that the write concern error is from the first failpoint
+            $this->assertSame(self::SHUTDOWN_IN_PROGRESS, $writeConcernError->getCode());
+        }
+
+        // Step 5: Disable the fail point
+        $client->getManager()->removeSubscriber($subscriber);
+        $this->configureFailPoint([
+            'configureFailPoint' => 'failCommand',
+            'mode' => 'off',
+        ]);
+    }
 }

From 8e1181a14c4072519e1f663964f14d800b4e023b Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Tue, 17 Jan 2023 09:58:19 +0100
Subject: [PATCH 254/321] Fix: Remove duplicate word (#1038)

---
 tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
index ae0f88c2e..c45f981e9 100644
--- a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
+++ b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
@@ -50,7 +50,7 @@ public function provideTypes()
             // Note: additional tests in testTypeObject
             'object(stdClass)' => ['object', new stdClass()],
             'object(BSONDocument)' => ['object', new BSONDocument()],
-            // Note: additional tests tests in testTypeArray
+            // Note: additional tests in testTypeArray
             'array(indexed array)' => ['array', ['foo']],
             'array(BSONArray)' => ['array', new BSONArray()],
             'binData' => ['binData', new Binary('', 0)],

From a0e465232146c0238c9a8e2432e2a3f0b13ce59e Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Tue, 17 Jan 2023 09:59:24 +0100
Subject: [PATCH 255/321] Remove the words `easily` and `simply` (#1039)

---
 src/GridFS/ReadableStream.php           | 2 +-
 tests/Operation/WatchFunctionalTest.php | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/GridFS/ReadableStream.php b/src/GridFS/ReadableStream.php
index d76e06172..7c3d8be4b 100644
--- a/src/GridFS/ReadableStream.php
+++ b/src/GridFS/ReadableStream.php
@@ -224,7 +224,7 @@ public function seek(int $offset): void
         }
 
         /* If we are seeking to a subsequent chunk, we do not need to
-         * reinitalize the chunk iterator. Instead, we can simply move forward
+         * reinitalize the chunk iterator. Instead, we can move forward
          * to $this->chunkOffset.
          */
         $numChunks = $this->chunkOffset - $lastChunkOffset;
diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php
index e55be49d5..0a5671379 100644
--- a/tests/Operation/WatchFunctionalTest.php
+++ b/tests/Operation/WatchFunctionalTest.php
@@ -673,9 +673,9 @@ public function testInitialCursorIsNotClosed(): void
         /* The spec requests that we assert that the cursor returned from the
          * aggregate command is not closed on the driver side. We will verify
          * this by checking that the cursor ID is non-zero and that libmongoc
-         * reports the cursor as alive. While the cursor ID is easily accessed
-         * through ChangeStream, we'll need to use reflection to access the
-         * internal Cursor and call isDead(). */
+         * reports the cursor as alive. While the cursor ID is accessed through
+         * ChangeStream, we'll need to use reflection to access the internal
+         * Cursor and call isDead(). */
         $this->assertNotEquals('0', (string) $changeStream->getCursorId());
 
         $rc = new ReflectionClass(ChangeStream::class);

From fa7a21473f231c21ceee3e25a6ed028f33b7ffc9 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Tue, 17 Jan 2023 10:49:36 +0100
Subject: [PATCH 256/321] Add PHP open tag to examples (#1037)

* [Documentation] Add PHP open tag to examples

* Update docs/faq.txt

Co-authored-by: Andreas Braun 

Co-authored-by: Andreas Braun 
---
 docs/reference/method/MongoDBCollection-find.txt       | 2 ++
 docs/reference/method/MongoDBCollection-findOne.txt    | 4 ++++
 docs/reference/method/MongoDBCollection-updateMany.txt | 2 ++
 docs/reference/method/MongoDBCollection-updateOne.txt  | 2 ++
 docs/tutorial/crud.txt                                 | 2 ++
 5 files changed, 12 insertions(+)

diff --git a/docs/reference/method/MongoDBCollection-find.txt b/docs/reference/method/MongoDBCollection-find.txt
index 2a5e2afb7..303b70421 100644
--- a/docs/reference/method/MongoDBCollection-find.txt
+++ b/docs/reference/method/MongoDBCollection-find.txt
@@ -56,6 +56,8 @@ returned. It also limits the results to 5 documents.
 
 .. code-block:: php
 
+   test->restaurants;
 
    $cursor = $collection->find(
diff --git a/docs/reference/method/MongoDBCollection-findOne.txt b/docs/reference/method/MongoDBCollection-findOne.txt
index 3ebd2b531..5e4c32f3b 100644
--- a/docs/reference/method/MongoDBCollection-findOne.txt
+++ b/docs/reference/method/MongoDBCollection-findOne.txt
@@ -62,6 +62,8 @@ special BSON type, the query criteria for selecting a restaurant must use the
 
 .. code-block:: php
 
+   test;
 
    $zip = $database->zips->findOne(['_id' => '10036']);
@@ -80,6 +82,8 @@ returned.
 
 .. code-block:: php
 
+   test->restaurants;
 
    $restaurant = $collection->findOne(
diff --git a/docs/reference/method/MongoDBCollection-updateMany.txt b/docs/reference/method/MongoDBCollection-updateMany.txt
index 73092e78d..c30978824 100644
--- a/docs/reference/method/MongoDBCollection-updateMany.txt
+++ b/docs/reference/method/MongoDBCollection-updateMany.txt
@@ -57,6 +57,8 @@ The following example updates all of the documents with the ``borough`` of
 
 .. code-block:: php
 
+   test->restaurants;
 
    $updateResult = $collection->updateMany(
diff --git a/docs/reference/method/MongoDBCollection-updateOne.txt b/docs/reference/method/MongoDBCollection-updateOne.txt
index d7fbd1573..5fe29405c 100644
--- a/docs/reference/method/MongoDBCollection-updateOne.txt
+++ b/docs/reference/method/MongoDBCollection-updateOne.txt
@@ -59,6 +59,8 @@ The following example updates one document with the ``restaurant_id`` of
 
 .. code-block:: php
 
+   test->restaurants;
 
    $updateResult = $collection->updateOne(
diff --git a/docs/tutorial/crud.txt b/docs/tutorial/crud.txt
index a5c0d431c..b5588acb1 100644
--- a/docs/tutorial/crud.txt
+++ b/docs/tutorial/crud.txt
@@ -380,6 +380,8 @@ An equivalent filter could be constructed using the :query:`$regex` operator:
 
 .. code-block:: php
 
+    ['$regex' => '^garden', '$options' => 'i'],
        'state' => 'TX',

From d3ea59f956d53256160c651fbefcd68b0c094eae Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 18 Jan 2023 08:30:18 +0100
Subject: [PATCH 257/321] [Documentation] Remove the words `easily` and
 `simply` (#1041)

---
 docs/tutorial/tailable-cursor.txt | 8 ++++----
 docs/upgrade.txt                  | 4 ++--
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/docs/tutorial/tailable-cursor.txt b/docs/tutorial/tailable-cursor.txt
index 2c84b080b..370a642a1 100644
--- a/docs/tutorial/tailable-cursor.txt
+++ b/docs/tutorial/tailable-cursor.txt
@@ -98,10 +98,10 @@ preceding example to use the Iterator methods directly:
    Calling ``$cursor->next()`` after the ``while`` loop naturally ends would
    throw an exception, since all results on the cursor have been exhausted.
 
-The purpose of this example is simply to demonstrate the functional equivalence
-between ``foreach`` and manual iteration with PHP's :php:`Iterator `
-API. For normal cursors, there is little reason to manually iterate results
-instead of a concise ``foreach`` loop.
+The purpose of this example is to demonstrate the functional equivalence between
+``foreach`` and manual iteration with PHP's :php:`Iterator `API.
+For normal cursors, there is little reason to manually iterate results instead
+of a concise ``foreach`` loop.
 
 Iterating a Tailable Cursor
 ---------------------------
diff --git a/docs/upgrade.txt b/docs/upgrade.txt
index ff1bc90ee..d73d57e6c 100644
--- a/docs/upgrade.txt
+++ b/docs/upgrade.txt
@@ -118,8 +118,8 @@ problematic:
   original BSON type.
 
 - Numerically-indexed PHP arrays would be serialized as BSON documents if there
-  was a gap in their key sequence. Such gaps were easily caused by unsetting a
-  key to remove an element and forgetting to numerically reindex the array.
+  was a gap in their key sequence. Such gaps were caused by unsetting a key to
+  remove an element and forgetting to numerically reindex the array.
 
 The |php-library|'s :phpclass:`BSONDocument ` and
 :phpclass:`BSONArray ` classes address these concerns

From c39b0c0bb4d94786bd8892f3a4531b5eaa7f32a1 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 18 Jan 2023 08:30:49 +0100
Subject: [PATCH 258/321] [Documentation] Remove duplicate word (#1040)

---
 docs/reference/method/MongoDBModelIndexInfo-getName.txt | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/docs/reference/method/MongoDBModelIndexInfo-getName.txt b/docs/reference/method/MongoDBModelIndexInfo-getName.txt
index ba4fa55e2..b37c66216 100644
--- a/docs/reference/method/MongoDBModelIndexInfo-getName.txt
+++ b/docs/reference/method/MongoDBModelIndexInfo-getName.txt
@@ -17,8 +17,7 @@ Definition
 
    Return the index name. This correlates with the return value of
    :phpmethod:`MongoDB\\Collection::createIndex()`. An index name may be derived
-   from the ``$key`` parameter or or explicitly specified via the ``name``
-   option.
+   from the ``$key`` parameter or explicitly specified via the ``name`` option.
 
    .. code-block:: php
 

From 3e14c151088ad219f7a0b41f85e96aba43f43c72 Mon Sep 17 00:00:00 2001
From: Oskar Stark 
Date: Wed, 18 Jan 2023 08:41:42 +0100
Subject: [PATCH 259/321] [Documentation] Spelling (#1042)

---
 docs/faq.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/faq.txt b/docs/faq.txt
index 72801e161..9cdd9a250 100644
--- a/docs/faq.txt
+++ b/docs/faq.txt
@@ -152,7 +152,7 @@ failure:
 - "connection timeout" could indicate a routing or firewall issue, or perhaps
   a timeout due to latency.
 - "socket timeout" suggests that a connection *was* established at some point
-  but was dropped or otherwise timeout out due to latency.
+  but was dropped or otherwise timed out due to latency.
 - "TLS handshake failed" suggests something related to TLS or OCSP verification
   and is sometimes indicative of misconfigured TLS certificates.
 

From d791f4bbb3ddf49e42db17d37386d909a2275e8a Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Wed, 18 Jan 2023 12:55:01 +0100
Subject: [PATCH 260/321] PHPLIB-619: Unskip Azure encryption test (#1044)

---
 tests/SpecTests/ClientSideEncryptionSpecTest.php | 1 -
 1 file changed, 1 deletion(-)

diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index fcab1de58..2dfe30f09 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -63,7 +63,6 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase
 
     /** @var array */
     private static $incompleteTests = [
-        'azureKMS: Insert a document with auto encryption using Azure KMS provider' => 'RHEL platform is missing Azure root certificate (PHPLIB-619)',
         'explain: Explain a find with deterministic encryption' => 'crypt_shared does not add apiVersion field to explain commands (PHPLIB-947, SERVER-69564)',
         'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)',
         'timeoutMS: remaining timeoutMS applied to find to get keyvault data' => 'Not yet implemented (PHPC-1760)',

From 9894020913a2f9b59a2aab65f85c0dcd046a7ef7 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Thu, 19 Jan 2023 14:46:40 +0100
Subject: [PATCH 261/321] PHPLIB-1037: Don't error when creating context for
 sharded clusters using mongodb+srv connection string (#1045)

---
 tests/UnifiedSpecTests/UnifiedTestRunner.php | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)

diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php
index ba3e5242b..e3df84cff 100644
--- a/tests/UnifiedSpecTests/UnifiedTestRunner.php
+++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php
@@ -35,8 +35,6 @@
 use function PHPUnit\Framework\assertIsString;
 use function PHPUnit\Framework\assertNotEmpty;
 use function PHPUnit\Framework\assertNotFalse;
-use function PHPUnit\Framework\assertStringContainsString;
-use function PHPUnit\Framework\assertStringStartsWith;
 use function preg_match;
 use function preg_replace;
 use function sprintf;
@@ -48,7 +46,6 @@
 use const DIRECTORY_SEPARATOR;
 use const FILTER_VALIDATE_BOOLEAN;
 use const PATH_SEPARATOR;
-use const PHP_URL_HOST;
 
 /**
  * Unified test runner.
@@ -531,14 +528,15 @@ private function createContext(): Context
             // We assume the internal client URI has multiple mongos hosts
             $multiMongosUri = $this->internalClientUri;
 
-            /* TODO: If an SRV URI is provided, we can consider connecting and
-             * checking the topology for multiple mongoses and then selecting a
-             * single mongos to reconstruct a single mongos URI; however, that
-             * may omit necessary URI options provided by TXT records. */
-            assertStringStartsWith('mongodb://', $multiMongosUri);
-            assertStringContainsString(',', parse_url($multiMongosUri, PHP_URL_HOST));
-
-            $singleMongosUri = self::removeMultipleHosts($multiMongosUri);
+            if (strpos($multiMongosUri, 'mongodb+srv://') === 0) {
+                /* TODO: If an SRV URI is provided, we can consider connecting and
+                 * checking the topology for multiple mongoses and then selecting a
+                 * single mongos to reconstruct a single mongos URI; however, that
+                 * may omit necessary URI options provided by TXT records. */
+                $singleMongosUri = $multiMongosUri;
+            } else {
+                $singleMongosUri = self::removeMultipleHosts($multiMongosUri);
+            }
 
             $context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri);
         }

From 843a422a1f9d4eff39202b5652669a8eed60e4d8 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Mon, 23 Jan 2023 08:32:31 +0100
Subject: [PATCH 262/321] Skip unrelated builds for documentation (#1043)

---
 .github/workflows/coding-standards.yml | 4 ++++
 .github/workflows/docs.yml             | 4 ++++
 .github/workflows/static-analysis.yml  | 4 ++++
 .github/workflows/tests.yml            | 4 ++++
 4 files changed, 16 insertions(+)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index 06b999ced..e9207b68b 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -6,11 +6,15 @@ on:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths-ignore:
+      - "docs/**"
   push:
     branches:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths-ignore:
+      - "docs/**"
 
 jobs:
   phpcs:
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index e8cd6ebc3..a7a1413a8 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -6,11 +6,15 @@ on:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths:
+      - "docs/**"
   push:
     branches:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths:
+      - "docs/**"
 
 jobs:
   giza:
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index a1a09ca43..67c605e8c 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -6,11 +6,15 @@ on:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths-ignore:
+      - "docs/**"
   push:
     branches:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths-ignore:
+      - "docs/**"
 
 jobs:
   psalm:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index e3372df4c..52de03cf6 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -6,11 +6,15 @@ on:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths-ignore:
+      - "docs/**"
   push:
     branches:
       - "v*.*"
       - "master"
       - "feature/*"
+    paths-ignore:
+      - "docs/**"
 
 jobs:
   phpunit:

From fb7a1bf302ae50cd284a552ba3f9352f5daa7733 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Mon, 30 Jan 2023 09:05:36 +0000
Subject: [PATCH 263/321] PHPLIB-1068: Sync rewrapManyDataKey unified spec test
 (#1046)

---
 .../rewrapManyDataKey.json                    | 30 +++++++++++++++----
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json
index 89860de0c..6b3c9664a 100644
--- a/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json
+++ b/tests/UnifiedSpecTests/client-side-encryption/rewrapManyDataKey.json
@@ -321,7 +321,10 @@
               "modifiedCount": 4,
               "deletedCount": 0,
               "upsertedCount": 0,
-              "upsertedIds": {}
+              "upsertedIds": {},
+              "insertedIds": {
+                "$$unsetOrMatches": {}
+              }
             }
           }
         }
@@ -503,7 +506,10 @@
               "modifiedCount": 4,
               "deletedCount": 0,
               "upsertedCount": 0,
-              "upsertedIds": {}
+              "upsertedIds": {},
+              "insertedIds": {
+                "$$unsetOrMatches": {}
+              }
             }
           }
         }
@@ -687,7 +693,10 @@
               "modifiedCount": 4,
               "deletedCount": 0,
               "upsertedCount": 0,
-              "upsertedIds": {}
+              "upsertedIds": {},
+              "insertedIds": {
+                "$$unsetOrMatches": {}
+              }
             }
           }
         }
@@ -873,7 +882,10 @@
               "modifiedCount": 4,
               "deletedCount": 0,
               "upsertedCount": 0,
-              "upsertedIds": {}
+              "upsertedIds": {},
+              "insertedIds": {
+                "$$unsetOrMatches": {}
+              }
             }
           }
         }
@@ -1055,7 +1067,10 @@
               "modifiedCount": 4,
               "deletedCount": 0,
               "upsertedCount": 0,
-              "upsertedIds": {}
+              "upsertedIds": {},
+              "insertedIds": {
+                "$$unsetOrMatches": {}
+              }
             }
           }
         }
@@ -1218,7 +1233,10 @@
               "modifiedCount": 5,
               "deletedCount": 0,
               "upsertedCount": 0,
-              "upsertedIds": {}
+              "upsertedIds": {},
+              "insertedIds": {
+                "$$unsetOrMatches": {}
+              }
             }
           }
         },

From 5f0de79b70180387f0ae541181960bcfcb0a5cdc Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 21 Mar 2023 07:00:45 -0400
Subject: [PATCH 264/321] Update giza install instructions

---
 CONTRIBUTING.md | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7ed676815..892db70c7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -165,8 +165,14 @@ repository:
  * Clone the
    [mongodb/docs-php-library](https://github.com/mongodb/docs-php-library) tools
    repository.
- * Install [giza](https://pypi.python.org/pypi/giza/), as noted in the tools
-   README.
+ * Create and activate Python 2.7 virtual environment if necessary.
+
+   ```
+   $ virtualenv -p python2.7 venv
+   $ source venv/bin/activate
+   ```
+ * Install [giza](https://pypi.python.org/pypi/giza/) according to the instructions
+   in the [mongodb/docs-tools](https://github.com/mongodb/docs-tools) README.
  * Sync your working copy of the documentation to the `source/` directory with
    `rsync -a --delete /path/to/mongo-php-library/docs/ source/`.
  * Build the documentation with `giza make publish`. You can suppress

From 65d7418fdb5467d9fa42b77415402aa8f5cee12e Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 21 Mar 2023 09:42:28 -0400
Subject: [PATCH 265/321] Remove extra slashes in method signature

---
 docs/reference/method/MongoDBCollection-explain.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/reference/method/MongoDBCollection-explain.txt b/docs/reference/method/MongoDBCollection-explain.txt
index 68a8965aa..600f203b8 100644
--- a/docs/reference/method/MongoDBCollection-explain.txt
+++ b/docs/reference/method/MongoDBCollection-explain.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function explain(MongoDB\\Operation\\Explainable $explainable, array $options = []): array|object
+      function explain(MongoDB\Operation\Explainable $explainable, array $options = []): array|object
 
    This method has the following parameters:
 

From 8dcb543036fe982ed91f3e3496138fc5688750d2 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Wed, 22 Mar 2023 15:55:55 +0800
Subject: [PATCH 266/321] PHPLIB-1089: Sync CSFLE spec tests for state
 collection namespace validation (#1051)

Synced with mongodb/specifications@8f6f4a3a1841c0301ca057e96afca6f4f46711a2
---
 .../ClientSideEncryptionSpecTest.php          |  196 ++
 .../tests/fle2-CreateCollection.json          |  252 +--
 ...EncryptedFields-vs-EncryptedFieldsMap.json |    6 +-
 .../tests/fle2-Range-Date-Aggregate.json      |  514 +++++
 .../tests/fle2-Range-Date-Correctness.json    | 1842 ++++++++++++++++
 .../tests/fle2-Range-Date-Delete.json         |  459 ++++
 .../fle2-Range-Date-FindOneAndUpdate.json     |  538 +++++
 .../tests/fle2-Range-Date-InsertFind.json     |  505 +++++
 .../tests/fle2-Range-Date-Update.json         |  540 +++++
 .../tests/fle2-Range-Decimal-Aggregate.json   | 1908 ++++++++++++++++
 .../tests/fle2-Range-Decimal-Correctness.json | 1158 ++++++++++
 .../tests/fle2-Range-Decimal-Delete.json      | 1133 ++++++++++
 .../fle2-Range-Decimal-FindOneAndUpdate.json  | 1930 ++++++++++++++++
 .../tests/fle2-Range-Decimal-InsertFind.json  | 1899 ++++++++++++++++
 .../tests/fle2-Range-Decimal-Update.json      | 1934 +++++++++++++++++
 ...fle2-Range-DecimalPrecision-Aggregate.json |  590 +++++
 ...e2-Range-DecimalPrecision-Correctness.json | 1650 ++++++++++++++
 .../fle2-Range-DecimalPrecision-Delete.json   |  493 +++++
 ...nge-DecimalPrecision-FindOneAndUpdate.json |  612 ++++++
 ...le2-Range-DecimalPrecision-InsertFind.json |  577 +++++
 .../fle2-Range-DecimalPrecision-Update.json   |  612 ++++++
 .../tests/fle2-Range-Double-Aggregate.json    | 1138 ++++++++++
 .../tests/fle2-Range-Double-Correctness.json  | 1160 ++++++++++
 .../tests/fle2-Range-Double-Delete.json       |  749 +++++++
 .../fle2-Range-Double-FindOneAndUpdate.json   | 1160 ++++++++++
 .../tests/fle2-Range-Double-InsertFind.json   | 1129 ++++++++++
 .../tests/fle2-Range-Double-Update.json       | 1164 ++++++++++
 .../fle2-Range-DoublePrecision-Aggregate.json |  586 +++++
 ...le2-Range-DoublePrecision-Correctness.json | 1650 ++++++++++++++
 .../fle2-Range-DoublePrecision-Delete.json    |  491 +++++
 ...ange-DoublePrecision-FindOneAndUpdate.json |  608 ++++++
 ...fle2-Range-DoublePrecision-InsertFind.json |  577 +++++
 .../fle2-Range-DoublePrecision-Update.json    |  612 ++++++
 .../tests/fle2-Range-Int-Aggregate.json       |  490 +++++
 .../tests/fle2-Range-Int-Correctness.json     | 1644 ++++++++++++++
 .../tests/fle2-Range-Int-Delete.json          |  437 ++++
 .../fle2-Range-Int-FindOneAndUpdate.json      |  512 +++++
 .../tests/fle2-Range-Int-InsertFind.json      |  481 ++++
 .../tests/fle2-Range-Int-Update.json          |  516 +++++
 .../tests/fle2-Range-Long-Aggregate.json      |  490 +++++
 .../tests/fle2-Range-Long-Correctness.json    | 1644 ++++++++++++++
 .../tests/fle2-Range-Long-Delete.json         |  437 ++++
 .../fle2-Range-Long-FindOneAndUpdate.json     |  512 +++++
 .../tests/fle2-Range-Long-InsertFind.json     |  481 ++++
 .../tests/fle2-Range-Long-Update.json         |  516 +++++
 .../tests/fle2-Range-WrongType.json           |  162 ++
 46 files changed, 38565 insertions(+), 129 deletions(-)
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json

diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index 2dfe30f09..87e309cc9 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -64,6 +64,202 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase
     /** @var array */
     private static $incompleteTests = [
         'explain: Explain a find with deterministic encryption' => 'crypt_shared does not add apiVersion field to explain commands (PHPLIB-947, SERVER-69564)',
+        'fle2-Range-Date-Aggregate: FLE2 Range Date. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Delete: FLE2 Range Date. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-FindOneAndUpdate: FLE2 Range Date. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-InsertFind: FLE2 Range Date. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Date-Update: FLE2 Range Date. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Aggregate: FLE2 Range Decimal. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Delete: FLE2 Range Decimal. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-FindOneAndUpdate: FLE2 Range Decimal. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-InsertFind: FLE2 Range Decimal. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Aggregate: FLE2 Range DecimalPrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Delete: FLE2 Range DecimalPrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-FindOneAndUpdate: FLE2 Range DecimalPrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-InsertFind: FLE2 Range DecimalPrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DecimalPrecision-Update: FLE2 Range DecimalPrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Decimal-Update: FLE2 Range Decimal. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Aggregate: FLE2 Range Double. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Delete: FLE2 Range Double. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-FindOneAndUpdate: FLE2 Range Double. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-InsertFind: FLE2 Range Double. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Aggregate: FLE2 Range DoublePrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Delete: FLE2 Range DoublePrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-FindOneAndUpdate: FLE2 Range DoublePrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-InsertFind: FLE2 Range DoublePrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-DoublePrecision-Update: FLE2 Range DoublePrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Double-Update: FLE2 Range Double. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Aggregate: FLE2 Range Int. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Delete: FLE2 Range Int. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-FindOneAndUpdate: FLE2 Range Int. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-InsertFind: FLE2 Range Int. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Int-Update: FLE2 Range Int. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Aggregate: FLE2 Range Long. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Delete: FLE2 Range Long. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-FindOneAndUpdate: FLE2 Range Long. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-InsertFind: FLE2 Range Long. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-Long-Update: FLE2 Range Long. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-WrongType: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2-Range-WrongType: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
         'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)',
         'timeoutMS: remaining timeoutMS applied to find to get keyvault data' => 'Not yet implemented (PHPC-1760)',
     ];
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
index 9f8db41f8..7f4f38161 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
@@ -21,9 +21,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -60,7 +60,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -68,7 +68,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -76,7 +76,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -101,7 +101,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -110,7 +110,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -119,7 +119,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -137,7 +137,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -152,7 +152,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -167,7 +167,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -184,9 +184,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -745,9 +745,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -762,9 +762,9 @@
               ]
             },
             "default.encryptedCollection.esc": {
-              "escCollection": "encryptedCollection",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -801,7 +801,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -809,7 +809,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -817,7 +817,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -842,7 +842,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -851,7 +851,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -860,7 +860,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -878,7 +878,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -893,7 +893,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -908,7 +908,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -925,9 +925,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -974,9 +974,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1059,9 +1059,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1098,7 +1098,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1106,7 +1106,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1114,7 +1114,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1139,7 +1139,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1148,7 +1148,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1157,7 +1157,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1175,7 +1175,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1190,7 +1190,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1205,7 +1205,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1222,9 +1222,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -1278,9 +1278,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1302,9 +1302,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1325,7 +1325,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1333,7 +1333,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1341,7 +1341,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1366,7 +1366,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1375,7 +1375,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1384,7 +1384,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1402,7 +1402,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1417,7 +1417,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1432,7 +1432,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1449,9 +1449,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -1510,9 +1510,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1542,7 +1542,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1551,7 +1551,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1560,7 +1560,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1594,9 +1594,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1618,9 +1618,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1641,7 +1641,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1649,7 +1649,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1657,7 +1657,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1683,9 +1683,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1706,7 +1706,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1714,7 +1714,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1722,7 +1722,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1738,7 +1738,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1747,7 +1747,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1756,7 +1756,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1774,7 +1774,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1789,7 +1789,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1804,7 +1804,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1821,9 +1821,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -1874,7 +1874,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1883,7 +1883,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1892,7 +1892,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1926,9 +1926,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1950,9 +1950,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1973,7 +1973,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1981,7 +1981,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1989,7 +1989,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -2021,7 +2021,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -2029,7 +2029,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -2037,7 +2037,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -2053,7 +2053,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2062,7 +2062,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2071,7 +2071,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2089,7 +2089,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -2104,7 +2104,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -2119,7 +2119,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -2136,9 +2136,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -2201,7 +2201,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2210,7 +2210,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2219,7 +2219,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
index 911b42863..42cd4bbc9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
@@ -94,9 +94,9 @@
           },
           "encryptedFieldsMap": {
             "default.default": {
-              "escCollection": "esc",
-              "eccCollection": "ecc",
-              "ecocCollection": "ecoc",
+              "escCollection": "enxcol_.default.esc",
+              "eccCollection": "enxcol_.default.ecc",
+              "ecocCollection": "enxcol_.default.ecoc",
               "fields": []
             }
           }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json
new file mode 100644
index 000000000..a35321cd3
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json
@@ -0,0 +1,514 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+            }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Date. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$gt": {
+                      "$date": {
+                        "$numberLong": "0"
+                      }
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedDate": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json
new file mode 100644
index 000000000..5832e8541
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json
@@ -0,0 +1,1842 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+            }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gte": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "1"
+                  }
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$lt": {
+                  "$date": {
+                    "$numberLong": "1"
+                  }
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$lte": {
+                  "$date": {
+                    "$numberLong": "1"
+                  }
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$lt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "200"
+                  }
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be less than the range maximum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                },
+                "$lt": {
+                  "$date": {
+                    "$numberLong": "2"
+                  }
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gte": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                },
+                "$lte": {
+                  "$date": {
+                    "$numberLong": "200"
+                  }
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$in": [
+                  {
+                    "$date": {
+                      "$numberLong": "0"
+                    }
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Insert out of range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "-1"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "value must be greater than or equal to the minimum value"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Insert min and max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 200,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "200"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {},
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 200,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "200"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$gte": {
+                      "$date": {
+                        "$numberLong": "0"
+                      }
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$gt": {
+                      "$date": {
+                        "$numberLong": "1"
+                      }
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$lt": {
+                      "$date": {
+                        "$numberLong": "1"
+                      }
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$lte": {
+                      "$date": {
+                        "$numberLong": "1"
+                      }
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$lt": {
+                      "$date": {
+                        "$numberLong": "0"
+                      }
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$gt": {
+                      "$date": {
+                        "$numberLong": "200"
+                      }
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be less than the range maximum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$gt": {
+                      "$date": {
+                        "$numberLong": "0"
+                      }
+                    },
+                    "$lt": {
+                      "$date": {
+                        "$numberLong": "2"
+                      }
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$date": {
+                      "$numberLong": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$date": {
+                      "$numberLong": "1"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$gte": {
+                      "$date": {
+                        "$numberLong": "0"
+                      }
+                    },
+                    "$lte": {
+                      "$date": {
+                        "$numberLong": "200"
+                      }
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDate": {
+                    "$in": [
+                      {
+                        "$date": {
+                          "$numberLong": "0"
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$numberDouble": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gte": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "value type is a date"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json
new file mode 100644
index 000000000..b5856e762
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json
@@ -0,0 +1,459 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+            }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Date. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedDate": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDate": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json
new file mode 100644
index 000000000..a59258a46
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json
@@ -0,0 +1,538 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+            }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Date. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDate": {
+                  "$date": {
+                    "$numberLong": "2"
+                  }
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedDate": {
+              "$date": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedDate": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDate": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hyDcE6QQjPrYJaIS/n7evEZFYcm31Tj89CpEYGF45cI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ty4cnzJdAlbQKnh7px3GEYjBnvO+jIOaKjoTRDtmh3M=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json
new file mode 100644
index 000000000..4357fafee
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json
@@ -0,0 +1,505 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+            }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Date. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedDate": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json
new file mode 100644
index 000000000..fd170554f
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json
@@ -0,0 +1,540 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+            }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+            }
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Date. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDate": {
+                "$date": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedDate": {
+                "$gt": {
+                  "$date": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDate": {
+                  "$date": {
+                    "$numberLong": "2"
+                  }
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDate": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedDate": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedDate": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDate",
+                        "bsonType": "date",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$date": {
+                              "$numberLong": "0"
+                            }
+                          },
+                          "max": {
+                            "$date": {
+                              "$numberLong": "200"
+                            }
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDate": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDate": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hyDcE6QQjPrYJaIS/n7evEZFYcm31Tj89CpEYGF45cI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ty4cnzJdAlbQKnh7px3GEYjBnvO+jIOaKjoTRDtmh3M=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json
new file mode 100644
index 000000000..73d2cf489
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json
@@ -0,0 +1,1908 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimal",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Decimal. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$gt": {
+                      "$numberDecimal": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedDecimal": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rbf3AeBEv4wWFAKknqDxRW5cLNkFvbIs6iJjc6LShQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0l86Ag5OszXpa78SlOUV3K9nff5iC1p0mRXtLg9M1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hn6yuxFHodeyu7ISlhYrbSf9pTiH4TDEvbYLWjTwFO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zdf4y2etKBuIpkEU1zMwoCkCsdisfXZCh8QPamm+drY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rOQ9oMdiK5xxGH+jPzOvwVqdGGnF3+HkJXxn81s6hp4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "61aKKsE3+BJHHWYvs3xSIBvlRmKswmaOo5rygQJguUg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KuDb/GIzqDM8wv7m7m8AECiWJbae5EKKtJRugZx7kR0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Q+t8t2TmNUiCIorVr9F3AlVnX+Mpt2ZYvN+s8UGict8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJRZIpKxUgHyL83kW8cvfjkxN3z6WoNnUg+SQw+LK+k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnUsYjip8SvW0+m9mR5WWTkpK+p6uwJ6yBUAlBnFKMk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PArHlz+yPRYDycAP/PgnI/AkP8Wgmfg++Vf4UG1Bf0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wnIh53Q3jeK8jEBe1n8kJLa89/H0BxO26ZU8SRIAs9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4F8U59gzBLGhq58PEWQk2nch+R0Va7eTUoxMneReUIA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ihKagIW3uT1dm22ROr/g5QaCpxZVj2+Fs/YSdM2Noco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EJtUOOwjkrPUi9mavYAi+Gom9Y2DuFll7aDwo4mq0M0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dIkr8dbaVRQFskAVT6B286BbcBBt1pZPEOcTZqk4ZcI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aYVAcZYkH/Tieoa1XOjE/zCy5AJcVTHjS0NG2QB7muA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sBidL6y8TenseetpioIAAtn0lK/7C8MoW4JXpVYi3z8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Dd2klU/t4R86c2WJcJDAd57k/N7OjvYSO5Vf8KH8sw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I3jZ92WEVmZmgaIkLbuWhBxl7EM6bEjiEttgBJunArA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aGHoQMlgJoGvArjfIbc3nnkoc8SWBxcrN7hSmjMRzos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bpiWPnF/KVBQr5F6MEwc5ZZayzIRvQOLDAm4ntwOi8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI7QVKbE6avWgDD9h4QKyFlnTxFCwd2iLySKakxNR/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XGsge0CnoaXgE3rcpKm8AEeku5QVfokS3kcI+JKV1lk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JQxlryW2Q5WOwfrjAnaZxDvC83Dg6sjRVP5zegf2WiM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YFuHKJOfoqp1iGVxoFjx7bLYgVdsN4GuUFxEgO9HJ5s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z6vUdiCR18ylKomf08uxcQHeRtmyav7/Ecvzz4av3k4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SPGo1Ib5AiP/tSllL7Z5PAypvnKdwJLzt8imfIMSEJQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m94Nh6PFFQFLIib9Cu5LAKavhXnagSHG6F5EF8lD96I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pfEkQI98mB+gm1+JbmVurPAODMFPJ4E8DnqfVyUWbSo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DNj3OVRLbr43s0vd+rgWghOL3FqeO/60npdojC8Ry/M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kAYIQrjHVu49W8FTxyxJeiLVRWWjC9fPcBn+Hx1F+Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aCSO7UVOpoQvu/iridarxkxV1SVxU1i9HVSYXUAeXk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Gh6hTP/yj1IKlXQ+Q69KTfMlGZjEcXoRLGbQHNFo/1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/gDgIFQ4tAlJk3GN48IS5Qa5IPmErwGk8CHxAbp6gs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PICyimwPjxpusyKxNssOOwUotAUbygpyEtORsVGXT8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4lu+cBHyAUvuxC6JUNyHLzHsCogGSWFFnUCkDwfQdgI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pSndkmoNUJwXjgkbkgOrT5f9nSvuoMEZOkwAN9ElRaE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tyW+D4i26QihNM5MuBM+wnt5AdWGSJaJ4X5ydc9iWTU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9Syjr8RoxUgPKr+O5rsCu07AvcebA4P8IVKyS1NVLWc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "67tPfDYnK2tmrioI51fOBG0ygajcV0pLo5+Zm/rEW7U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y0EiPRxYTuS1eVTIaPQUQBBxwkyxNckbePvKgChwd0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NWd+2veAaeXQgR3vCvzlI4R1WW67D5YsVLdoXfdb8qg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PY5RQqKQsL2GqBBSPNOEVpojNFRX/NijCghIpxD6CZk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lcvwTyEjFlssCJtdjRpdN6oY+C7bxZY+WA+QAqzj9zg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWE7XRNylvTwO/9Fv56dNqUaQWMmESNS/GNIwgBaEI0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ijwlrUeS8nRYqK1F8kiCYF0mNDolEZS+/lJO1Lg93C8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8KzV+qYGYuIjoNj8eEpnTuHrMYuhzphl80rS6wrODuU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wDyTLjSEFF895hSQsHvmoEQVS6KIkZOtq1c9dVogm9I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SGrtPuMYCjUrfKF0Pq/thdaQzmGBMUvlwN3ORIu9tHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KySHON3hIoUk4xWcwTqk6IL0kgjzjxgMBObVIkCGvk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hBIdS9j0XJPeT4ot73ngELkpUoSixvRBvdOL9z48jY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Tx6um0q9HjS5ZvlFhvukpI6ORnyrXMWVW1OoxvgqII0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zFKlyfX5H81+d4A4J3FKn4T5JfG+OWtR06ddyX4Mxas=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cGgCDuPV7MeMMYEDpgOupqyNP4BQ4H7rBnd2QygumgM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IPaUoy98v11EoglTpJ4kBlEawoZ8y7BPwzjLYBpkvHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Pfo4Am6tOWAyZNn8G9W5HWWGC3ZWmX0igI/RRB870Ro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fnTSjd7bC1Udoq6iM7UDnHAC/lsIXSHp/Gy332qw+/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fApBgVRrTDyEumkeWs5p3ag9KB48SbU4Si0dl7Ns9rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QxudfBItgoCnUj5NXVnSmWH3HK76YtKkMmzn4lyyUYY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sSOvwhKa29Wq94bZ5jGIiJQGbG1uBrKSBfOYBz/oZeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FdaMgwwJ0NKsqmPZLC5oE+/0D74Dfpvig3LaI5yW5Fs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sRWBy12IERN43BSZIrnBfC9+zFBUdvjTlkqIH81NGt4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/4tIRpxKhoOwnXAiFn1Z7Xmric4USOIfKvTYQXk3QTc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": {
+                "$numberInt": "1"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RGTjNVEsNJb+DG7DpPOam8rQWD5HZAMpRyiTQaw7tk8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I93Md7QNPGmEEGYU1+VVCqBPBEvXdqHPtTJtMOn06Yk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "GecBFQ1PemlECWZWCl7f74vmsL6eB6mzQ9n6tK6FYfs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QpjhZl+O1ORifgtCZuWAdcP6OKL7IZ2cA46v8FJcV28=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RlQWwhU+uVv0a+9IB5cUkEfvHBvOw3B1Sx6WfPWMqes=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubb81XTC7U+4tcNzf1oYvOY6gR5hC2Izqx54f4GuJ0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6M4Q5NMQ9TqNnjzGOxIkiUIY8TEL0I3XD1QnhefQUqU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BtInzk9t2FFMCEY6AQ7zN8jwrrZEs2irSv6q0Q4NaIw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vxXfETu9cuBIpRBo3jUUU04mJIH/aAhLX8K6VI5Xv0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wXPCdS+q23zi1bkPnaVG2j0PsVtxdeSLJ//h6J1x8RU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KY3KkfBAsN2l80wbpj41G0gwBR5KmmFnZcagg7D3ENk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI8NFAxXCX4VOnY5X73K6KI/Yspd3aR94KV39MhJlAw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nFxH0UC3mATKA6Vboz+QX/hAjj19kF/SH6H5Cne7qC0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q8hYqIYaIi7nOdG/7qQZYnz8Bsacfi66M1nVku4SH08=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4saA92R4arp4anvD9xFtze+sNcQqTEhPHyl1h70A8NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DbIziOBRRyeQS6RtBR09E37LV+CTKrEjGoRMLSpG6eE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Fv80Plp/7w2gnVqrwawLd6qhJ10G4NCDm3re67cNq4Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "T/T2oiQCBBES4YN7EodzPRdabZSFlYIClHBym+bQUZE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZQgHD3l46Ujqtbnj1VbbeM29C9wJzOhz+yZ/7XdSrxk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ltlFKzWvyZvHxDFOYDd/XXJ6kUiJj0ln2HTCEz2o4Z4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "flW8A7bltC1u8bzx0WJtxosGJdOVsJFfbx33jxnpFGg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SXO+92QbMKwUSG2t27ciunV1c3VvFkUuDmSczpRe008=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+KioGs1GM+xRBzFE67ePTWj04KMSE5/Y6qUF7nJ5kvU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L3xNVbh6YH+RzqABN+5Jgb7T234Efpn766DmUvxIxgg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hPF+60mBYPjh21dEmPlBhKgyc9S2qLtTkypYvnqP2Fc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EletRsETy2HcjaPIm2c8CkT7ch/P3pJJDC8hasepcSU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "r5bMXUaNKqLPxZ+TG9HYTG4aSDgcpim27rN8rQFkM0w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Q7Erdr8+/S0wUEDDIqlS5XjBVWvhZY65K0uUDb6+Ns=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xEcnhXy35hbXNVBPOOt3TUHbxvKfQ48KjA9b6/rbMqQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "T8bEpiQNgsEudXvyKE9SZlSvbpV/LUaslsdqgSFltyo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hIoiaF2YjnxDbODfhFEB+JGZ5nf8suD3Shck5bwQ3N0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qnA6qzejeRJ0rsZaZ0zOvKAaXyxt5lpscKQNYFZNl4k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "anAKCL2DN/le2VaP0n2ucYSEH/DaaEH/8Sa4OqTZsRA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JCZlBJaFm618oWYSnT9Jr1MtwFVw4BZjOzO+5yWgR90=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yxyk4n9762WzcDVGnTn4jCqUnSMIVCrLDIjCX1QVj34=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fDI6fdKvDJwim5/CQwWZEzcrXE3LHgy7FTtffcC7tXE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Vex+gcz5T+WkzsVZQrkqUR2ryyZbnaOGuWpYvjN0zCw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8TLEXz+Gbbp6llHpZXVjLsdlYY9f6hrKpHVpyfDe0RY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7fTyt5BrunypS65TfOzFW2E2qdIuT4SLeDeGlbQoJCs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8fKGrkqN0/KuSjyXgDBmRauDKrSa//JBKRWHEB9xBf4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s4codmG7uN4ss6P357jL21lazEe90M9GOK5WrOknSV0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RkSpua8XF+NUdxVDU90EbLUTTyZFX3tt3atBTroFaRk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "LnTCuCDyAHK5B9KXzjtwGmWB+qergQk2OCjnIx9MI2A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cBFh0virAX4pVXf/udIGI2951i0+0aZAdJcBVGtYnT4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "G54X6myQXWZ5fw/G31en3QbdgfXzL9+hFTtJpnWMqDI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EdsiiuezcsFJFnYIyGjCOhnqMj1BOwTB5EFxN+ERUkg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dVH9MXLtk0WTwGQ3xmrhOqfropMUkDW3o6paNPGl3NU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sB3HqXKWY3pKbuEH8BTbfNIGfbY+7/ZbOc3XC+JRNNI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WHyDk62Xhqbo4/iie2aLIM4x2uuAjv6102dJSHI58oM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pNUFuHpeNRDUZ/NrtII2c6sNc9eGR1lIUlIyXKERA+0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UPa+pdCqnN0bfAptdzldQOSd01gidrDKy8KhWrpSKAI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "l+7dOAlo+HUffMqFYXL6pgUFeTbwOM9CjKQLxEoLtc4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SRnDXV/rN6C8xwMutv9E1luv3DOUio3VkgPr8Cpm7Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QcH6gl+gX7xZ7OWhUNQMbndJy0Piz49pDo6RsnLkVSA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "t+uL4DnfsI/Zll/KXWW1cOKX3Hu8WIkm3pt9efCVSAQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "myutHDctku/+Uug/nD8gRbYvmx/IovtoAAC2/fz2oHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6C+cjD0e0nSCP6cPqQYbNG7SlOd6Mfvi8hyfm7Ng+D8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zg01JSoOj9oBKT0S1ldJucXzY5AKgreS+h2xJreWTOs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7qQ80/FjodHl1m1py/Oii0/9C/xWbLdhaRXQ+kkCP10=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YwWMNH07vL6c5Nhg+MRnVByhzUunu8y0VLM9z/XvR5U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dle8bU98+fudAbc14SToZFkwvV3tcYVsjDug0NWljpc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "J+eKL1vPJmlzltvhI6Li5Fz/TJmi3Ng+ehRTcs46API=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB3XzfFygLwC3WHkj0up+VbEd25KKoce1vOpG/5bwK4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vnVnmOnL+z2pqwE+A6cVKS0Iwy4F4/2IiElJca9bUQM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+lG5r/Fpqry3BtFuvY67+RntmHAMDoLVOSGc6ZoXPb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L5MXQertqc6uj7ADe8aWKbd1sYHPCE7P1VYVg9Zc3VI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "imKONuZgopt0bhM3GMX2WVPwQYMTobuUUEdhcLfHs4c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "eOkU1J1uVbiVFWBerbXsSIVcF2nqiicTkFy4x7kFHB8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gI0uDhXeoH/UatDQKEf4qo8FHzWZDhb/wuWTqbq/ID4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cOkd5Aa3btYhtojE/smsF/PJnULqQ4NNqTkU6KXTFmo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "AWNJMs1MTe294oFipp8Y6P0CjpkZ4qCZoClQF3XcHq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6gJtlzXOFhGYrVbTuRMmvMlDTwXdNtR9aGBlHZPwIMw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "LEmwVGA/xsEG7UrcOoYLFu6KCXgijzFznenknuDacm8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mIRFPTXRrGaPtp/Ydij2jgkRe4uoUvAKxW2d8b9zYL0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "B+Uv2u48WALOO0L311z+eryjYQzKJVMfdHMZPhOAFmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "INXXp0wDyVCq+NtfIrrC2ciETmyW/dWB/48/u4yLEZ4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "se7DGo8XrlrQDLEcco1tZrQt9kDe+0RTyl2bw/quG4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vr0m2+Zk9lbN6UgWCyn8xJWJOokU3IDYab5U5q1+CgQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XI+eJ8Gy2JktG1gICgoj1qpsfy1tKmH0kglWbaQH6DA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A+UCuNnuAUqnQzspA6TVqUPRmtZmpSex5HFw7THRxs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xaH2Ehfljd19uo0Fvb3iwkdaiWEVQd2YPoitgEPkhSM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "S/iZBJGcc8+qZxyMtab65MMBoSglybwk3x58Nb86gnY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "w14ZE5qqY5YgkS4Zcs9YNbrQbY1XfGOOHNn9bOYnFVQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0MhGd/jEF1vjkKGp+ZMn9SjLK54jkp9W4Hg+Sp/oxaI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "92QZ73e/NRTYgCm4aifaKth6aAsKnLLccBc0zx/qUTY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WOjzemCgFJOiGIp81RSVh/tFlzSTj9eFWcBnsiv2Ycs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DrsP9CmfKPjw5yLL8bnSeAxfNzAwlb+Z8OqCiKgBY7o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lMogqg8veBv6mri3/drMe9afJiKMvevkmGcw9BedfLo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "TxqwNcY8Tg2MPpNdkPBwvfpuTttSYRHU26DGECKYQ9o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "l0u1b4b4vYACWIwfnB7PZac4oDEgjQZCzHruNPTgAIY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "iVSGQ+cCfhbWIrY/v/WBORK92elu9gfRKyGhr6r/k00=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yK1forG50diEXte8ECzjfpHeYsPyuQ/dgxbxn/nzY5k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gIfTLCD3VwnOwkC0zPXWTqaITxX6ZplA69PO2a6zolc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "O/Zxlgh3WqpzJ7+Sd8XWMVID4/GXJUUWaSqfgDUi3b0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZQ6yv368zwahUqSUYH/StL0Qgz/TwS1CzlMjVDvCciI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m2rPEYkjwyiKdonMrKlcF7hya4lFOAUwEePJ3SgrNx8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Mq0yl5iVKlq71bT/dT/fXOWf2n90bTnXFnOdGDN0JOc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6qDGMXipPLC2O6EAAMjO2F9xx4rdqZso4IkPpH2304U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jvQHRQQa2RIszE2LX2Hv2LbRhYawJ6qmtRt8HZzFQXg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ovJXQrkZlpeHRciKyE/WWNm5O389gRgzx1W+Dw596X4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "a4kgRNvYctGYqyQv9qScL/WkljTYVylJ9pE9KDULlxU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qV4Q48vPiCJMTjljotzYKI/zfExWpkKOSHGcAjGyDig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jtI7zbBF+QW/aYYTkn90zzyHLXLgmy7l1bzgMb2oqic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q0KmJl9txPdn962UNvnfe6UFhdk9YaFZuTm33F+csso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ULNdEqeZJgtmNOhN/Y9INzsE9AnxWYwOMn+pIbRXIFs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "R4oz9+wkdjpKe5tE1jpG7IURAnfvS5fLP4LrD5cZfTE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qG5Z7VhwSu/HT/YFTgDzyAAzJKq51xPw2HeEV5btYC4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OM/1DmIIZ5Qyhtq8TGkHTBEMVKjAnKRZMRXYtTG8ctc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2R5vZbljLXnDFA99YfGuRB7pAdPJVKsT25zLNMC0fUk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OMbavF2EmdAz1fHkLV3ctFEUDfriKhoT2gidwHZ9z1o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MWT4Zrw3/vVvTYMa1Is5Pjr3wEwnBfnEAPPUAHKQhNU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tBkRPfG9yxfKocQx5pAJX0oEHKPL0Tgtr+0UYe09InE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lqxpnDR/H0YgH7RcfKoNoaaRhe1SIazIeMbQ1fu9y3Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "utT1UdR22PWOTrOkZauztX613lAplV4eh/ejTRb7ZSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "S+Y2yFyKi/a6FXhih4yGo29X8I8OT6/zwEoX6NMKT4o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QSjVppg29x6oS5yBg8OFjrFt0tuTpWCuKxfIy0k8YnE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y3r6/Xsfvsl3HksXlVYkJgHUqpQGfICxg3x9f8Zw1qM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BSltHzEwDjFN4du9rDHAPvl22atlcTioEtt+gC5L1tk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0arGXjSN0006UnXbrWsGqhvBair569DeFDUME3Df3rA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s/DumaMad08S+PBUUcrS+v42K0z8HgcdiQtrFAEu2Qs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EzJ8Y8N0OQBTlnvrK82PdevDNZZO4E6CNgYVu8Cj6Ks=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VA4vr8jBPI5QdiPrULzzZjBMIUbG3V7Slg5zm0bFcKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YAOvEB2ZLtq9LQiFViBHWaxxWVVonC2rNYj9tN9s3L0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hgaHMo9aAGS+nBwvqnTjZO+YkiQPY1c1XcIYeaYKHyI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YvaoLt3ZpH0atB0tNzwMjpoxRYJXl0DqSjisMJiGVBE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EMmW6CptFsiLoPOi5/uAJQ2FmeLg6mCpuVLLrRWk7Mc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1jQsNMarSnarlYmXEuoFokeBMg/090qUD9wqo1Zn8Gs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hupXNKhRpJxpyDAAP1TgJ5JMZh9lhbMk6s7D7dMS3C8=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json
new file mode 100644
index 000000000..89b7bd311
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json
@@ -0,0 +1,1158 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimal",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "0.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gte": {
+                  "$numberDecimal": "0.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "1.0"
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$lt": {
+                  "$numberDecimal": "1.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$lte": {
+                  "$numberDecimal": "1.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "0.0"
+                },
+                "$lt": {
+                  "$numberDecimal": "2.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$in": [
+                  {
+                    "$numberDecimal": "0.0"
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$gte": {
+                      "$numberDecimal": "0.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$gt": {
+                      "$numberDecimal": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$lt": {
+                      "$numberDecimal": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$lte": {
+                      "$numberDecimal": "1.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$gt": {
+                      "$numberDecimal": "0.0"
+                    },
+                    "$lt": {
+                      "$numberDecimal": "2.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$numberDecimal": "0.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$numberDecimal": "1.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimal": {
+                    "$in": [
+                      {
+                        "$numberDecimal": "0.0"
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberInt": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gte": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json
new file mode 100644
index 000000000..0463be1c6
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json
@@ -0,0 +1,1133 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimal",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Decimal. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedDecimal": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDecimal": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rbf3AeBEv4wWFAKknqDxRW5cLNkFvbIs6iJjc6LShQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0l86Ag5OszXpa78SlOUV3K9nff5iC1p0mRXtLg9M1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hn6yuxFHodeyu7ISlhYrbSf9pTiH4TDEvbYLWjTwFO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zdf4y2etKBuIpkEU1zMwoCkCsdisfXZCh8QPamm+drY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rOQ9oMdiK5xxGH+jPzOvwVqdGGnF3+HkJXxn81s6hp4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "61aKKsE3+BJHHWYvs3xSIBvlRmKswmaOo5rygQJguUg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KuDb/GIzqDM8wv7m7m8AECiWJbae5EKKtJRugZx7kR0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Q+t8t2TmNUiCIorVr9F3AlVnX+Mpt2ZYvN+s8UGict8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJRZIpKxUgHyL83kW8cvfjkxN3z6WoNnUg+SQw+LK+k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnUsYjip8SvW0+m9mR5WWTkpK+p6uwJ6yBUAlBnFKMk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PArHlz+yPRYDycAP/PgnI/AkP8Wgmfg++Vf4UG1Bf0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wnIh53Q3jeK8jEBe1n8kJLa89/H0BxO26ZU8SRIAs9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4F8U59gzBLGhq58PEWQk2nch+R0Va7eTUoxMneReUIA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ihKagIW3uT1dm22ROr/g5QaCpxZVj2+Fs/YSdM2Noco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EJtUOOwjkrPUi9mavYAi+Gom9Y2DuFll7aDwo4mq0M0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dIkr8dbaVRQFskAVT6B286BbcBBt1pZPEOcTZqk4ZcI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aYVAcZYkH/Tieoa1XOjE/zCy5AJcVTHjS0NG2QB7muA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sBidL6y8TenseetpioIAAtn0lK/7C8MoW4JXpVYi3z8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Dd2klU/t4R86c2WJcJDAd57k/N7OjvYSO5Vf8KH8sw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I3jZ92WEVmZmgaIkLbuWhBxl7EM6bEjiEttgBJunArA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aGHoQMlgJoGvArjfIbc3nnkoc8SWBxcrN7hSmjMRzos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bpiWPnF/KVBQr5F6MEwc5ZZayzIRvQOLDAm4ntwOi8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI7QVKbE6avWgDD9h4QKyFlnTxFCwd2iLySKakxNR/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XGsge0CnoaXgE3rcpKm8AEeku5QVfokS3kcI+JKV1lk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JQxlryW2Q5WOwfrjAnaZxDvC83Dg6sjRVP5zegf2WiM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YFuHKJOfoqp1iGVxoFjx7bLYgVdsN4GuUFxEgO9HJ5s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z6vUdiCR18ylKomf08uxcQHeRtmyav7/Ecvzz4av3k4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SPGo1Ib5AiP/tSllL7Z5PAypvnKdwJLzt8imfIMSEJQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m94Nh6PFFQFLIib9Cu5LAKavhXnagSHG6F5EF8lD96I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pfEkQI98mB+gm1+JbmVurPAODMFPJ4E8DnqfVyUWbSo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DNj3OVRLbr43s0vd+rgWghOL3FqeO/60npdojC8Ry/M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kAYIQrjHVu49W8FTxyxJeiLVRWWjC9fPcBn+Hx1F+Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aCSO7UVOpoQvu/iridarxkxV1SVxU1i9HVSYXUAeXk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Gh6hTP/yj1IKlXQ+Q69KTfMlGZjEcXoRLGbQHNFo/1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/gDgIFQ4tAlJk3GN48IS5Qa5IPmErwGk8CHxAbp6gs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PICyimwPjxpusyKxNssOOwUotAUbygpyEtORsVGXT8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4lu+cBHyAUvuxC6JUNyHLzHsCogGSWFFnUCkDwfQdgI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pSndkmoNUJwXjgkbkgOrT5f9nSvuoMEZOkwAN9ElRaE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tyW+D4i26QihNM5MuBM+wnt5AdWGSJaJ4X5ydc9iWTU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9Syjr8RoxUgPKr+O5rsCu07AvcebA4P8IVKyS1NVLWc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "67tPfDYnK2tmrioI51fOBG0ygajcV0pLo5+Zm/rEW7U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y0EiPRxYTuS1eVTIaPQUQBBxwkyxNckbePvKgChwd0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NWd+2veAaeXQgR3vCvzlI4R1WW67D5YsVLdoXfdb8qg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PY5RQqKQsL2GqBBSPNOEVpojNFRX/NijCghIpxD6CZk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lcvwTyEjFlssCJtdjRpdN6oY+C7bxZY+WA+QAqzj9zg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWE7XRNylvTwO/9Fv56dNqUaQWMmESNS/GNIwgBaEI0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ijwlrUeS8nRYqK1F8kiCYF0mNDolEZS+/lJO1Lg93C8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8KzV+qYGYuIjoNj8eEpnTuHrMYuhzphl80rS6wrODuU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wDyTLjSEFF895hSQsHvmoEQVS6KIkZOtq1c9dVogm9I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SGrtPuMYCjUrfKF0Pq/thdaQzmGBMUvlwN3ORIu9tHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KySHON3hIoUk4xWcwTqk6IL0kgjzjxgMBObVIkCGvk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hBIdS9j0XJPeT4ot73ngELkpUoSixvRBvdOL9z48jY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Tx6um0q9HjS5ZvlFhvukpI6ORnyrXMWVW1OoxvgqII0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zFKlyfX5H81+d4A4J3FKn4T5JfG+OWtR06ddyX4Mxas=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cGgCDuPV7MeMMYEDpgOupqyNP4BQ4H7rBnd2QygumgM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IPaUoy98v11EoglTpJ4kBlEawoZ8y7BPwzjLYBpkvHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Pfo4Am6tOWAyZNn8G9W5HWWGC3ZWmX0igI/RRB870Ro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fnTSjd7bC1Udoq6iM7UDnHAC/lsIXSHp/Gy332qw+/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fApBgVRrTDyEumkeWs5p3ag9KB48SbU4Si0dl7Ns9rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QxudfBItgoCnUj5NXVnSmWH3HK76YtKkMmzn4lyyUYY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sSOvwhKa29Wq94bZ5jGIiJQGbG1uBrKSBfOYBz/oZeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FdaMgwwJ0NKsqmPZLC5oE+/0D74Dfpvig3LaI5yW5Fs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sRWBy12IERN43BSZIrnBfC9+zFBUdvjTlkqIH81NGt4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/4tIRpxKhoOwnXAiFn1Z7Xmric4USOIfKvTYQXk3QTc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json
new file mode 100644
index 000000000..d0e296777
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json
@@ -0,0 +1,1930 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimal",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Decimal. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDecimal": {
+                  "$numberDecimal": "2"
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedDecimal": {
+              "$numberDecimal": "1"
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedDecimal": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDecimal": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rbf3AeBEv4wWFAKknqDxRW5cLNkFvbIs6iJjc6LShQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0l86Ag5OszXpa78SlOUV3K9nff5iC1p0mRXtLg9M1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hn6yuxFHodeyu7ISlhYrbSf9pTiH4TDEvbYLWjTwFO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zdf4y2etKBuIpkEU1zMwoCkCsdisfXZCh8QPamm+drY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rOQ9oMdiK5xxGH+jPzOvwVqdGGnF3+HkJXxn81s6hp4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "61aKKsE3+BJHHWYvs3xSIBvlRmKswmaOo5rygQJguUg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KuDb/GIzqDM8wv7m7m8AECiWJbae5EKKtJRugZx7kR0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Q+t8t2TmNUiCIorVr9F3AlVnX+Mpt2ZYvN+s8UGict8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJRZIpKxUgHyL83kW8cvfjkxN3z6WoNnUg+SQw+LK+k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnUsYjip8SvW0+m9mR5WWTkpK+p6uwJ6yBUAlBnFKMk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PArHlz+yPRYDycAP/PgnI/AkP8Wgmfg++Vf4UG1Bf0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wnIh53Q3jeK8jEBe1n8kJLa89/H0BxO26ZU8SRIAs9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4F8U59gzBLGhq58PEWQk2nch+R0Va7eTUoxMneReUIA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ihKagIW3uT1dm22ROr/g5QaCpxZVj2+Fs/YSdM2Noco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EJtUOOwjkrPUi9mavYAi+Gom9Y2DuFll7aDwo4mq0M0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dIkr8dbaVRQFskAVT6B286BbcBBt1pZPEOcTZqk4ZcI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aYVAcZYkH/Tieoa1XOjE/zCy5AJcVTHjS0NG2QB7muA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sBidL6y8TenseetpioIAAtn0lK/7C8MoW4JXpVYi3z8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Dd2klU/t4R86c2WJcJDAd57k/N7OjvYSO5Vf8KH8sw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I3jZ92WEVmZmgaIkLbuWhBxl7EM6bEjiEttgBJunArA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aGHoQMlgJoGvArjfIbc3nnkoc8SWBxcrN7hSmjMRzos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bpiWPnF/KVBQr5F6MEwc5ZZayzIRvQOLDAm4ntwOi8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI7QVKbE6avWgDD9h4QKyFlnTxFCwd2iLySKakxNR/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XGsge0CnoaXgE3rcpKm8AEeku5QVfokS3kcI+JKV1lk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JQxlryW2Q5WOwfrjAnaZxDvC83Dg6sjRVP5zegf2WiM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YFuHKJOfoqp1iGVxoFjx7bLYgVdsN4GuUFxEgO9HJ5s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z6vUdiCR18ylKomf08uxcQHeRtmyav7/Ecvzz4av3k4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SPGo1Ib5AiP/tSllL7Z5PAypvnKdwJLzt8imfIMSEJQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m94Nh6PFFQFLIib9Cu5LAKavhXnagSHG6F5EF8lD96I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pfEkQI98mB+gm1+JbmVurPAODMFPJ4E8DnqfVyUWbSo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DNj3OVRLbr43s0vd+rgWghOL3FqeO/60npdojC8Ry/M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kAYIQrjHVu49W8FTxyxJeiLVRWWjC9fPcBn+Hx1F+Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aCSO7UVOpoQvu/iridarxkxV1SVxU1i9HVSYXUAeXk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Gh6hTP/yj1IKlXQ+Q69KTfMlGZjEcXoRLGbQHNFo/1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/gDgIFQ4tAlJk3GN48IS5Qa5IPmErwGk8CHxAbp6gs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PICyimwPjxpusyKxNssOOwUotAUbygpyEtORsVGXT8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4lu+cBHyAUvuxC6JUNyHLzHsCogGSWFFnUCkDwfQdgI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pSndkmoNUJwXjgkbkgOrT5f9nSvuoMEZOkwAN9ElRaE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tyW+D4i26QihNM5MuBM+wnt5AdWGSJaJ4X5ydc9iWTU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9Syjr8RoxUgPKr+O5rsCu07AvcebA4P8IVKyS1NVLWc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "67tPfDYnK2tmrioI51fOBG0ygajcV0pLo5+Zm/rEW7U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y0EiPRxYTuS1eVTIaPQUQBBxwkyxNckbePvKgChwd0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NWd+2veAaeXQgR3vCvzlI4R1WW67D5YsVLdoXfdb8qg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PY5RQqKQsL2GqBBSPNOEVpojNFRX/NijCghIpxD6CZk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lcvwTyEjFlssCJtdjRpdN6oY+C7bxZY+WA+QAqzj9zg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWE7XRNylvTwO/9Fv56dNqUaQWMmESNS/GNIwgBaEI0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ijwlrUeS8nRYqK1F8kiCYF0mNDolEZS+/lJO1Lg93C8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8KzV+qYGYuIjoNj8eEpnTuHrMYuhzphl80rS6wrODuU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wDyTLjSEFF895hSQsHvmoEQVS6KIkZOtq1c9dVogm9I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SGrtPuMYCjUrfKF0Pq/thdaQzmGBMUvlwN3ORIu9tHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KySHON3hIoUk4xWcwTqk6IL0kgjzjxgMBObVIkCGvk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hBIdS9j0XJPeT4ot73ngELkpUoSixvRBvdOL9z48jY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Tx6um0q9HjS5ZvlFhvukpI6ORnyrXMWVW1OoxvgqII0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zFKlyfX5H81+d4A4J3FKn4T5JfG+OWtR06ddyX4Mxas=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cGgCDuPV7MeMMYEDpgOupqyNP4BQ4H7rBnd2QygumgM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IPaUoy98v11EoglTpJ4kBlEawoZ8y7BPwzjLYBpkvHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Pfo4Am6tOWAyZNn8G9W5HWWGC3ZWmX0igI/RRB870Ro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fnTSjd7bC1Udoq6iM7UDnHAC/lsIXSHp/Gy332qw+/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fApBgVRrTDyEumkeWs5p3ag9KB48SbU4Si0dl7Ns9rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QxudfBItgoCnUj5NXVnSmWH3HK76YtKkMmzn4lyyUYY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sSOvwhKa29Wq94bZ5jGIiJQGbG1uBrKSBfOYBz/oZeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FdaMgwwJ0NKsqmPZLC5oE+/0D74Dfpvig3LaI5yW5Fs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sRWBy12IERN43BSZIrnBfC9+zFBUdvjTlkqIH81NGt4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/4tIRpxKhoOwnXAiFn1Z7Xmric4USOIfKvTYQXk3QTc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": {
+                "$numberInt": "1"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Mr/laWHUijZT5VT3x2a7crb7wgd/UXOGz8jr8BVqBpM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wXVD/HSbBljko0jJcaxJ1nrzs2+pchLQqYR3vywS8SU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VDCpBYsJIxTfcI6Zgf7FTmKMxUffQv+Ys8zt5dlK76I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zYDslUwOUVNwTYkETfjceH/PU3bac9X3UuQyYJ19qK0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rAOmHSz18Jx107xpbv9fYcPOmh/KPAqge0PAtuhIRnc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BFOB1OGVUen7VsOuS0g8Ti7oDsTt2Yj/k/7ta8YAdGM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2fckE5SPs0GU+akDkUEM6mm0EtcV3WDE/sQsnTtodlk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mi9+aNjuwIvaMpSHENvKzKRAmX9cYguo2mXLvOoftHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "K6TWn4VcWWkz/gkUkLmbtwkG7SNeABICmLDnoYJFlLU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z+2/cEtGU0Fq7QJFNGA/0y4aWAsw0ncG6X0LYRqwS3c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rrSIf+lgcNZFbbUkS9BmE045jRWBpcBJXHzfMVEFuzE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KlHL3Kyje1/LMIfgbCqw1SolxffJvvgsYBV5y77wxuA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hzJ1YBoETmYeCh352dBmG8d8Wse/bUcqojTWpWQlgsc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lSdcllDXx8MA+s0GULjDA1lQkcV0L8/aHtZ6dM2pZ2c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "HGr7JLTTA7ksAnlmjSIwwdBVvgr3fv46/FTdiCPYpos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mMr25v1VwOEVZ8xaNUTHJCcsYqV+kwK6RzGYilxPtJ4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "129hJbziPJzNo0IoTU3bECdge0FtaPW8dm4dyNVNwYU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "doiLJ96qoo+v7NqIAZLq6BI5axV8Id8gT5vyJ1ZZ0PM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cW/Lcul3xYmfyvI/0x/+ybN78aQmBK1XIGs1EEU09N8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1aVIwzu9N5EJV9yEES+/g6hOTH7cA2NTcLIc59cu0wU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kw5tyl7Ew0r1wFyrN1mB9FiVW2hK2BxxxUuJDNWjyjQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ADAY2YBrm6RJBDY/eLLcfNxmSJku+mefz74gH66oyco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8gkqB1LojzPrstpFG7RHYmWxXpIlPDTqWnNsXH7XDRU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "TESfVQMDQjfTZmHmUeYUE2XrokJ6CcrsKx/GmypGjOw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qFM+HFVQ539S0Ouynd1fBHoemFxtU9PRxE5+Dq7Ljy4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jPiFgUZteSmOg4wf3bsEKCZzcnxmMoILsgp/GaZD+dM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YaWUgJhYgPNN7TkFK16H8SsQS226JguaVhOIQxZwQNQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x90/Qk3AgyaFsvWf2KUCu5XF3j76WFSjt/GrnG01060=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZGWybWL/xlEdMYRFCZDUoz10sywTf7U/7wufsb78lH0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8l4ganN66jIcdxfHAdYLaym/mdzUUQ8TViw3MDRySPc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c8p5XEGTqxqvRGVlR+nkxw9uUdoqDqTB0jlYQ361qMA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1ZGFLlpQBcU3zIUg8MmgWwFKVz/SaA7eSYFrfe3Hb70=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "34529174M77rHr3Ftn9r8jU4a5ztYtyVhMn1wryZSkU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YkQ4pxFWzc49MS0vZM6S8mNo4wAwo21rePBeF3C+9mI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MhOf4mYY00KKVhptOcXf0bXB7WfuuM801MRJg4vXPgc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7pbbD8ihNIYIBJ3tAUPGzHpFPpIeCTAk5L88qCB0/9w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "C9Q5PoNJTQo6pmNzXEEXUEqH22//UUWY1gqILcIywec=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "AqGVk1QjDNDLYWGRBX/nv9QdGR2SEgXZEhF0EWBAiSE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/sGI3VCbJUKATULJmhTayPOeVW+5MjWSvVCqS77sRbU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yOtbL0ih7gsuoxVtRrACMz+4N5uo7jIR7zzmtih2Beo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uA6dkb2Iyg9Su8UNDvZzkPx33kPZtWr/CCuEY+XgzUM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1DoSFPdHIplqZk+DyWAmEPckWwXw/GdB25NLmzeEZhk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OfDVS0T3ZuIXI/LNbTp6C9UbPIWLKiMy6Wx+9tqNl+g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3PZjHXbmG6GtPz+iapKtQ3yY4PoFFgjIy+fV2xQv1YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kaoLN0BoBWsmqE7kKkJQejATmLShd8qffcAmlhsxsGY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vpiw9KgQdegGmp7IJnSGX2miujRLU0xzs0ITTqbPW7c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NuXFf7xGUefYjIUTuMxNUTCfVHrF8oL0AT7dPv5Plk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8Tz53LxtfEBJ9eR+d2690kwNsqPV6XyKo2PlqZCbUrc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "e6zsOmHSyV8tyQtSX6BSwui6wK9v1xG3giY/IILJQ2w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2fedFMCxa2DzmIpfbDKGXhQg0PPwbUv6vIWdwwlvhms=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yEJKMFnWXTC8tJUfzCInzQRByNEPjHxpw4L4m8No91Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YbFuWwOiFuQyOzIJXDbOkCWC2DyrG+248TBuVCa1pXU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "w7IkwGdrguwDrar5+w0Z3va5wXyZ4VXJkDMISyRjPGo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YmJUoILTRJPhyIyWyXJTsQ6KSZHHbEpwPVup6Ldm/Ko=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FvMjcwVZJmfh6FP/yBg2wgskK+KHD8YVUY6WtrE8xbg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "h4HCtD4HyYz0nci49IVAa10Z4NJD/FHnRMV4sRX6qro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nC7BpXCmym+a0Is2kReM9cYN2M1Eh5rVo8fjms14Oiw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1qtVWaeVo649ZZZtN8gXbwLgMWGLhz8beODbvru0I7Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Ej+mC0QFyMNIiSjR939S+iGBm7dm+1xObu5IcF/OpbU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UQ8LbUG3cMegbr9yKfKanAPQE1EfPkFciVDrNqZ5GHY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4iI3mXIDjnX+ralk1HhJY43mZx2uTJM7hsv9MQzTX7E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0WQCcs3rvsasgohERHHCaBM4Iy6yomS4qJ5To3/yYiw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qDCTVPoue1/DOAGNAlUstdA9Sid8MgEY4e5EzHcVHRk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9F9Mus0UnlzHb8E8ImxgXtz6SU98YXD0JqswOKw/Bzs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pctHpHKVBBcsahQ6TNh6/1V1ZrqOtKSAPtATV6BJqh0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vfR3C/4cPkVdxtNaqtF/v635ONbhTf5WbwJM6s4EXNE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ejP43xUBIex6szDcqExAFpx1IE/Ksi5ywJ84GKDFRrs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jbP4AWYd3S2f3ejmMG7dS5IbrFol48UUoT+ve3JLN6U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CiDifI7958sUjNqJUBQULeyF7x0Up3loPWvYKw9uAuw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "e2dQFsiHqd2BFHNhlSxocjd+cPs4wkcUW/CnCz4KNuM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PJFckVmzBipqaEqsuP2mkjhJE4qhw36NhfQ9DcOHyEU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "S3MeuJhET/B8VcfZYDR9fvX0nscDj416jdDekhmK11s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CGVHZRXpuNtQviDB2Kj03Q8uvs4w3RwTgV847R7GwPw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yUGgmgyLrxbEpDVy89XN3c2cmFpZXWWmuJ/35zVZ+Jw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "inb6Q97mL1a9onfNTT8v9wsoi/fz7KXKq3p8j90AU9c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CCyYx/4npq9xGO1lsCo8ZJhFO9/tN7DB+/DTE778rYg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "LNnYw4fwbiAZu0kBdAHPEm/OFnreS+oArdB5O/l/I98=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "P006SxmUS/RjiQJVYPdMFnNo3827GIEmSzagggkg05Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "oyvwY+WsnYV6UHuPki1o0ILJ2jN4uyXf9yaUNtZJyBA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "36Lk3RHWh1wmtCWC/Yj6jNIo17U5y6SofAgQjzjVxD8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vOOo8FqeHnuO9mqOYjIb4vgwIwVyXZ5Y+bY5d9tGFUM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bJiDJjwQRNxqxlGjRm5lLziFhcfTDCnQ/qU1V85qcRg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2Qgrm1n0wUELAQnpkEiIHB856yv76q8jLbpiucetcm0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "5ciPOYxTK0WDwwYyfs7yiVymwtYQXDELLxmM4JLl4/o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "31dC2WUSIOKQc4jwT6PikfeYTwi80mTlh7P31T5KNQU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YluTV2Mu53EGCKLcWfHZb0BM/IPW2xJdG3vYlDMEsM4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dh/8lGo2Ek6KukSwutH6Q35iy8TgV0FN0SJqe0ZVHN8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EVw6HpIs3BKen2qY2gz4y5dw1JpXilfh07msZfQqJpc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FYolLla9L8EZMROEdWetozroU40Dnmwwx2jIMrr7c1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8M6k4QIutSIj6CM41vvkQtuFsaGrjoR9SZJVSLbfGKQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9LM0VoddDNHway442MqY+Z7vohB2UHau/cddshhzf40=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "66i8Ytco4Yq/FMl6pIRZazz3CZlu8fO2OI6Pne0pvHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2a/HgX+MjZxjXtSvHgF1yEpHMJBkl8Caee8XrJtn0WM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "frhBM662c4ZVG7mWP8K/HhRjd01lydW/cPcHnDjifqc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6k1T7Q1t668PBqv6fwpVnT1HWh7Am5LtbKvwPJKcpGU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UlJ5Edfusp8S/Pyhw6KTglIejmbr1HO0zUeHn/qFETA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jsxsB+1ECB3assUdoC333do9tYH+LglHmVSJHy4N8Hg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2nzIQxGYF7j3bGsIesECEOqhObKs/9ywknPHeJ3yges=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xJYKtuWrX90JrJVoYtnwP7Ce59XQGFYoalxpNfBXEH0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NLI5lriBTleGCELcHBtNnmnvwSRkHHaLOX4cKboMgTw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hUOQV0RmE5aJdJww1AR9rirJG4zOYPo+6cCkgn/BGvQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "h4G2Of76AgxcUziBwCyH+ayMOpdBWzg4yFrTfehSC2c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VuamM75RzGfQpj2/Y1jSVuQLrhy6OAwlZxjuQLB/9Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kn9+hLq7hvw02xr9vrplOCDXKBTuFhfbX7d5v/l85Pg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fAiGqKyLZpGngBYFbtYUYt8LUrJ49vYafiboifTDjxs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BxRILymgfVJCczqjUIWXcfrfSgrrYkxTM5VTg0HkZLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CrFY/PzfPU2zsFkGLu/dI6mEeizZzCR+uYgjZBAHro0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "AEbrIuwvXLTtYgMjOqnGQ8y8axUn5Ukrn7UZRSyfQVw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ouWeVH3PEFg+dKWlXc6BmqirJOaVWjJbMzZbCsce4dA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+hd6xFB+EG+kVP7WH4uMd1CLaWMnt5xJRaY/Guuga9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zmpGalfAOL3gmcUMJYcLYIRT/2VDO/1Dw4KdYZoNcng=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2PbHAoM/46J2UIZ/vyksKzmVVfxA7YUyIxWeL/N/vBk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7fD9x+zk5MVFesb59Klqiwwmve7P5ON/5COURXj5smE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tlrNQ4jaq051iaWonuv1sSrYhKkL1LtNZuHsvATha3s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fBodm28iClNpvlRyVq0dOdXQ08S7/N3aDwid+PdWvRo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "O+/nnRqT3Zv7yMMGug8GhKHaWy6u7BfRGtZoj0sdN1c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "5AZZ/RTMY4Photnm/cpXZr/HnFRi3eljacMsipkJLHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "oFVyo/kgoMxBIk2VE52ySSimeyU+Gr0EfCwapXnTpKA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z8v59DfcnviA0mzvnUk+URVO0UuqAWvtarEgJva/n1c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "P64GOntZ+zBJEHkigoh9FSxSO+rJTqR20z5aiGQ9an4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xMbSuDPfWuO/Dm7wuVl06GnzG9uzTlJJX9vFy7boGlY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kXPB19mRClxdH2UsHwlttS6lLU2uHvzuZgZz7kC45jU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NDVjVYXAw4k0w4tFzvs7QDq39aaU3HQor4I2XMKKnCk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uKw/+ErVfpTO1dGUfd3T/eWfZW3nUxXCdBGdjvHtZ88=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "av0uxEzWkizYWm0QUM/MN1hLibnxPvCWJKwjOV4yVQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ERwUC47dvgOBzIsEESMIioLYbFOxOe8PtJTnmDkKuHM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2gseKlG5Le12fS/vj4eaED4lturF16kAgJ1TpW3HxEE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7Cvg0Y3j/5i2F1TeXxlMmU7xwif5dCmwkZAOrVC5K2Y=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json
new file mode 100644
index 000000000..cea03e23f
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json
@@ -0,0 +1,1899 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimal",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Decimal. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedDecimal": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rbf3AeBEv4wWFAKknqDxRW5cLNkFvbIs6iJjc6LShQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0l86Ag5OszXpa78SlOUV3K9nff5iC1p0mRXtLg9M1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hn6yuxFHodeyu7ISlhYrbSf9pTiH4TDEvbYLWjTwFO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zdf4y2etKBuIpkEU1zMwoCkCsdisfXZCh8QPamm+drY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rOQ9oMdiK5xxGH+jPzOvwVqdGGnF3+HkJXxn81s6hp4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "61aKKsE3+BJHHWYvs3xSIBvlRmKswmaOo5rygQJguUg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KuDb/GIzqDM8wv7m7m8AECiWJbae5EKKtJRugZx7kR0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Q+t8t2TmNUiCIorVr9F3AlVnX+Mpt2ZYvN+s8UGict8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJRZIpKxUgHyL83kW8cvfjkxN3z6WoNnUg+SQw+LK+k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnUsYjip8SvW0+m9mR5WWTkpK+p6uwJ6yBUAlBnFKMk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PArHlz+yPRYDycAP/PgnI/AkP8Wgmfg++Vf4UG1Bf0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wnIh53Q3jeK8jEBe1n8kJLa89/H0BxO26ZU8SRIAs9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4F8U59gzBLGhq58PEWQk2nch+R0Va7eTUoxMneReUIA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ihKagIW3uT1dm22ROr/g5QaCpxZVj2+Fs/YSdM2Noco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EJtUOOwjkrPUi9mavYAi+Gom9Y2DuFll7aDwo4mq0M0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dIkr8dbaVRQFskAVT6B286BbcBBt1pZPEOcTZqk4ZcI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aYVAcZYkH/Tieoa1XOjE/zCy5AJcVTHjS0NG2QB7muA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sBidL6y8TenseetpioIAAtn0lK/7C8MoW4JXpVYi3z8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Dd2klU/t4R86c2WJcJDAd57k/N7OjvYSO5Vf8KH8sw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I3jZ92WEVmZmgaIkLbuWhBxl7EM6bEjiEttgBJunArA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aGHoQMlgJoGvArjfIbc3nnkoc8SWBxcrN7hSmjMRzos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bpiWPnF/KVBQr5F6MEwc5ZZayzIRvQOLDAm4ntwOi8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI7QVKbE6avWgDD9h4QKyFlnTxFCwd2iLySKakxNR/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XGsge0CnoaXgE3rcpKm8AEeku5QVfokS3kcI+JKV1lk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JQxlryW2Q5WOwfrjAnaZxDvC83Dg6sjRVP5zegf2WiM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YFuHKJOfoqp1iGVxoFjx7bLYgVdsN4GuUFxEgO9HJ5s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z6vUdiCR18ylKomf08uxcQHeRtmyav7/Ecvzz4av3k4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SPGo1Ib5AiP/tSllL7Z5PAypvnKdwJLzt8imfIMSEJQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m94Nh6PFFQFLIib9Cu5LAKavhXnagSHG6F5EF8lD96I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pfEkQI98mB+gm1+JbmVurPAODMFPJ4E8DnqfVyUWbSo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DNj3OVRLbr43s0vd+rgWghOL3FqeO/60npdojC8Ry/M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kAYIQrjHVu49W8FTxyxJeiLVRWWjC9fPcBn+Hx1F+Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aCSO7UVOpoQvu/iridarxkxV1SVxU1i9HVSYXUAeXk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Gh6hTP/yj1IKlXQ+Q69KTfMlGZjEcXoRLGbQHNFo/1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/gDgIFQ4tAlJk3GN48IS5Qa5IPmErwGk8CHxAbp6gs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PICyimwPjxpusyKxNssOOwUotAUbygpyEtORsVGXT8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4lu+cBHyAUvuxC6JUNyHLzHsCogGSWFFnUCkDwfQdgI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pSndkmoNUJwXjgkbkgOrT5f9nSvuoMEZOkwAN9ElRaE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tyW+D4i26QihNM5MuBM+wnt5AdWGSJaJ4X5ydc9iWTU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9Syjr8RoxUgPKr+O5rsCu07AvcebA4P8IVKyS1NVLWc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "67tPfDYnK2tmrioI51fOBG0ygajcV0pLo5+Zm/rEW7U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y0EiPRxYTuS1eVTIaPQUQBBxwkyxNckbePvKgChwd0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NWd+2veAaeXQgR3vCvzlI4R1WW67D5YsVLdoXfdb8qg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PY5RQqKQsL2GqBBSPNOEVpojNFRX/NijCghIpxD6CZk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lcvwTyEjFlssCJtdjRpdN6oY+C7bxZY+WA+QAqzj9zg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWE7XRNylvTwO/9Fv56dNqUaQWMmESNS/GNIwgBaEI0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ijwlrUeS8nRYqK1F8kiCYF0mNDolEZS+/lJO1Lg93C8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8KzV+qYGYuIjoNj8eEpnTuHrMYuhzphl80rS6wrODuU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wDyTLjSEFF895hSQsHvmoEQVS6KIkZOtq1c9dVogm9I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SGrtPuMYCjUrfKF0Pq/thdaQzmGBMUvlwN3ORIu9tHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KySHON3hIoUk4xWcwTqk6IL0kgjzjxgMBObVIkCGvk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hBIdS9j0XJPeT4ot73ngELkpUoSixvRBvdOL9z48jY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Tx6um0q9HjS5ZvlFhvukpI6ORnyrXMWVW1OoxvgqII0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zFKlyfX5H81+d4A4J3FKn4T5JfG+OWtR06ddyX4Mxas=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cGgCDuPV7MeMMYEDpgOupqyNP4BQ4H7rBnd2QygumgM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IPaUoy98v11EoglTpJ4kBlEawoZ8y7BPwzjLYBpkvHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Pfo4Am6tOWAyZNn8G9W5HWWGC3ZWmX0igI/RRB870Ro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fnTSjd7bC1Udoq6iM7UDnHAC/lsIXSHp/Gy332qw+/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fApBgVRrTDyEumkeWs5p3ag9KB48SbU4Si0dl7Ns9rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QxudfBItgoCnUj5NXVnSmWH3HK76YtKkMmzn4lyyUYY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sSOvwhKa29Wq94bZ5jGIiJQGbG1uBrKSBfOYBz/oZeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FdaMgwwJ0NKsqmPZLC5oE+/0D74Dfpvig3LaI5yW5Fs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sRWBy12IERN43BSZIrnBfC9+zFBUdvjTlkqIH81NGt4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/4tIRpxKhoOwnXAiFn1Z7Xmric4USOIfKvTYQXk3QTc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": {
+                "$numberInt": "1"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RGTjNVEsNJb+DG7DpPOam8rQWD5HZAMpRyiTQaw7tk8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I93Md7QNPGmEEGYU1+VVCqBPBEvXdqHPtTJtMOn06Yk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "GecBFQ1PemlECWZWCl7f74vmsL6eB6mzQ9n6tK6FYfs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QpjhZl+O1ORifgtCZuWAdcP6OKL7IZ2cA46v8FJcV28=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RlQWwhU+uVv0a+9IB5cUkEfvHBvOw3B1Sx6WfPWMqes=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubb81XTC7U+4tcNzf1oYvOY6gR5hC2Izqx54f4GuJ0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6M4Q5NMQ9TqNnjzGOxIkiUIY8TEL0I3XD1QnhefQUqU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BtInzk9t2FFMCEY6AQ7zN8jwrrZEs2irSv6q0Q4NaIw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vxXfETu9cuBIpRBo3jUUU04mJIH/aAhLX8K6VI5Xv0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wXPCdS+q23zi1bkPnaVG2j0PsVtxdeSLJ//h6J1x8RU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KY3KkfBAsN2l80wbpj41G0gwBR5KmmFnZcagg7D3ENk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI8NFAxXCX4VOnY5X73K6KI/Yspd3aR94KV39MhJlAw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nFxH0UC3mATKA6Vboz+QX/hAjj19kF/SH6H5Cne7qC0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q8hYqIYaIi7nOdG/7qQZYnz8Bsacfi66M1nVku4SH08=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4saA92R4arp4anvD9xFtze+sNcQqTEhPHyl1h70A8NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DbIziOBRRyeQS6RtBR09E37LV+CTKrEjGoRMLSpG6eE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Fv80Plp/7w2gnVqrwawLd6qhJ10G4NCDm3re67cNq4Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "T/T2oiQCBBES4YN7EodzPRdabZSFlYIClHBym+bQUZE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZQgHD3l46Ujqtbnj1VbbeM29C9wJzOhz+yZ/7XdSrxk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ltlFKzWvyZvHxDFOYDd/XXJ6kUiJj0ln2HTCEz2o4Z4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "flW8A7bltC1u8bzx0WJtxosGJdOVsJFfbx33jxnpFGg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SXO+92QbMKwUSG2t27ciunV1c3VvFkUuDmSczpRe008=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+KioGs1GM+xRBzFE67ePTWj04KMSE5/Y6qUF7nJ5kvU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L3xNVbh6YH+RzqABN+5Jgb7T234Efpn766DmUvxIxgg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hPF+60mBYPjh21dEmPlBhKgyc9S2qLtTkypYvnqP2Fc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EletRsETy2HcjaPIm2c8CkT7ch/P3pJJDC8hasepcSU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "r5bMXUaNKqLPxZ+TG9HYTG4aSDgcpim27rN8rQFkM0w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Q7Erdr8+/S0wUEDDIqlS5XjBVWvhZY65K0uUDb6+Ns=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xEcnhXy35hbXNVBPOOt3TUHbxvKfQ48KjA9b6/rbMqQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "T8bEpiQNgsEudXvyKE9SZlSvbpV/LUaslsdqgSFltyo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hIoiaF2YjnxDbODfhFEB+JGZ5nf8suD3Shck5bwQ3N0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qnA6qzejeRJ0rsZaZ0zOvKAaXyxt5lpscKQNYFZNl4k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "anAKCL2DN/le2VaP0n2ucYSEH/DaaEH/8Sa4OqTZsRA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JCZlBJaFm618oWYSnT9Jr1MtwFVw4BZjOzO+5yWgR90=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yxyk4n9762WzcDVGnTn4jCqUnSMIVCrLDIjCX1QVj34=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fDI6fdKvDJwim5/CQwWZEzcrXE3LHgy7FTtffcC7tXE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Vex+gcz5T+WkzsVZQrkqUR2ryyZbnaOGuWpYvjN0zCw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8TLEXz+Gbbp6llHpZXVjLsdlYY9f6hrKpHVpyfDe0RY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7fTyt5BrunypS65TfOzFW2E2qdIuT4SLeDeGlbQoJCs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8fKGrkqN0/KuSjyXgDBmRauDKrSa//JBKRWHEB9xBf4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s4codmG7uN4ss6P357jL21lazEe90M9GOK5WrOknSV0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RkSpua8XF+NUdxVDU90EbLUTTyZFX3tt3atBTroFaRk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "LnTCuCDyAHK5B9KXzjtwGmWB+qergQk2OCjnIx9MI2A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cBFh0virAX4pVXf/udIGI2951i0+0aZAdJcBVGtYnT4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "G54X6myQXWZ5fw/G31en3QbdgfXzL9+hFTtJpnWMqDI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EdsiiuezcsFJFnYIyGjCOhnqMj1BOwTB5EFxN+ERUkg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dVH9MXLtk0WTwGQ3xmrhOqfropMUkDW3o6paNPGl3NU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sB3HqXKWY3pKbuEH8BTbfNIGfbY+7/ZbOc3XC+JRNNI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WHyDk62Xhqbo4/iie2aLIM4x2uuAjv6102dJSHI58oM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pNUFuHpeNRDUZ/NrtII2c6sNc9eGR1lIUlIyXKERA+0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UPa+pdCqnN0bfAptdzldQOSd01gidrDKy8KhWrpSKAI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "l+7dOAlo+HUffMqFYXL6pgUFeTbwOM9CjKQLxEoLtc4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SRnDXV/rN6C8xwMutv9E1luv3DOUio3VkgPr8Cpm7Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QcH6gl+gX7xZ7OWhUNQMbndJy0Piz49pDo6RsnLkVSA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "t+uL4DnfsI/Zll/KXWW1cOKX3Hu8WIkm3pt9efCVSAQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "myutHDctku/+Uug/nD8gRbYvmx/IovtoAAC2/fz2oHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6C+cjD0e0nSCP6cPqQYbNG7SlOd6Mfvi8hyfm7Ng+D8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zg01JSoOj9oBKT0S1ldJucXzY5AKgreS+h2xJreWTOs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7qQ80/FjodHl1m1py/Oii0/9C/xWbLdhaRXQ+kkCP10=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YwWMNH07vL6c5Nhg+MRnVByhzUunu8y0VLM9z/XvR5U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dle8bU98+fudAbc14SToZFkwvV3tcYVsjDug0NWljpc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "J+eKL1vPJmlzltvhI6Li5Fz/TJmi3Ng+ehRTcs46API=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB3XzfFygLwC3WHkj0up+VbEd25KKoce1vOpG/5bwK4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vnVnmOnL+z2pqwE+A6cVKS0Iwy4F4/2IiElJca9bUQM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+lG5r/Fpqry3BtFuvY67+RntmHAMDoLVOSGc6ZoXPb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L5MXQertqc6uj7ADe8aWKbd1sYHPCE7P1VYVg9Zc3VI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "imKONuZgopt0bhM3GMX2WVPwQYMTobuUUEdhcLfHs4c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "eOkU1J1uVbiVFWBerbXsSIVcF2nqiicTkFy4x7kFHB8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gI0uDhXeoH/UatDQKEf4qo8FHzWZDhb/wuWTqbq/ID4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cOkd5Aa3btYhtojE/smsF/PJnULqQ4NNqTkU6KXTFmo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "AWNJMs1MTe294oFipp8Y6P0CjpkZ4qCZoClQF3XcHq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6gJtlzXOFhGYrVbTuRMmvMlDTwXdNtR9aGBlHZPwIMw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "LEmwVGA/xsEG7UrcOoYLFu6KCXgijzFznenknuDacm8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mIRFPTXRrGaPtp/Ydij2jgkRe4uoUvAKxW2d8b9zYL0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "B+Uv2u48WALOO0L311z+eryjYQzKJVMfdHMZPhOAFmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "INXXp0wDyVCq+NtfIrrC2ciETmyW/dWB/48/u4yLEZ4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "se7DGo8XrlrQDLEcco1tZrQt9kDe+0RTyl2bw/quG4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vr0m2+Zk9lbN6UgWCyn8xJWJOokU3IDYab5U5q1+CgQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XI+eJ8Gy2JktG1gICgoj1qpsfy1tKmH0kglWbaQH6DA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A+UCuNnuAUqnQzspA6TVqUPRmtZmpSex5HFw7THRxs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xaH2Ehfljd19uo0Fvb3iwkdaiWEVQd2YPoitgEPkhSM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "S/iZBJGcc8+qZxyMtab65MMBoSglybwk3x58Nb86gnY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "w14ZE5qqY5YgkS4Zcs9YNbrQbY1XfGOOHNn9bOYnFVQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0MhGd/jEF1vjkKGp+ZMn9SjLK54jkp9W4Hg+Sp/oxaI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "92QZ73e/NRTYgCm4aifaKth6aAsKnLLccBc0zx/qUTY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WOjzemCgFJOiGIp81RSVh/tFlzSTj9eFWcBnsiv2Ycs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DrsP9CmfKPjw5yLL8bnSeAxfNzAwlb+Z8OqCiKgBY7o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lMogqg8veBv6mri3/drMe9afJiKMvevkmGcw9BedfLo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "TxqwNcY8Tg2MPpNdkPBwvfpuTttSYRHU26DGECKYQ9o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "l0u1b4b4vYACWIwfnB7PZac4oDEgjQZCzHruNPTgAIY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "iVSGQ+cCfhbWIrY/v/WBORK92elu9gfRKyGhr6r/k00=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yK1forG50diEXte8ECzjfpHeYsPyuQ/dgxbxn/nzY5k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gIfTLCD3VwnOwkC0zPXWTqaITxX6ZplA69PO2a6zolc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "O/Zxlgh3WqpzJ7+Sd8XWMVID4/GXJUUWaSqfgDUi3b0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZQ6yv368zwahUqSUYH/StL0Qgz/TwS1CzlMjVDvCciI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m2rPEYkjwyiKdonMrKlcF7hya4lFOAUwEePJ3SgrNx8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Mq0yl5iVKlq71bT/dT/fXOWf2n90bTnXFnOdGDN0JOc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6qDGMXipPLC2O6EAAMjO2F9xx4rdqZso4IkPpH2304U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jvQHRQQa2RIszE2LX2Hv2LbRhYawJ6qmtRt8HZzFQXg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ovJXQrkZlpeHRciKyE/WWNm5O389gRgzx1W+Dw596X4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "a4kgRNvYctGYqyQv9qScL/WkljTYVylJ9pE9KDULlxU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qV4Q48vPiCJMTjljotzYKI/zfExWpkKOSHGcAjGyDig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jtI7zbBF+QW/aYYTkn90zzyHLXLgmy7l1bzgMb2oqic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q0KmJl9txPdn962UNvnfe6UFhdk9YaFZuTm33F+csso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ULNdEqeZJgtmNOhN/Y9INzsE9AnxWYwOMn+pIbRXIFs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "R4oz9+wkdjpKe5tE1jpG7IURAnfvS5fLP4LrD5cZfTE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qG5Z7VhwSu/HT/YFTgDzyAAzJKq51xPw2HeEV5btYC4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OM/1DmIIZ5Qyhtq8TGkHTBEMVKjAnKRZMRXYtTG8ctc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2R5vZbljLXnDFA99YfGuRB7pAdPJVKsT25zLNMC0fUk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OMbavF2EmdAz1fHkLV3ctFEUDfriKhoT2gidwHZ9z1o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MWT4Zrw3/vVvTYMa1Is5Pjr3wEwnBfnEAPPUAHKQhNU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tBkRPfG9yxfKocQx5pAJX0oEHKPL0Tgtr+0UYe09InE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lqxpnDR/H0YgH7RcfKoNoaaRhe1SIazIeMbQ1fu9y3Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "utT1UdR22PWOTrOkZauztX613lAplV4eh/ejTRb7ZSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "S+Y2yFyKi/a6FXhih4yGo29X8I8OT6/zwEoX6NMKT4o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QSjVppg29x6oS5yBg8OFjrFt0tuTpWCuKxfIy0k8YnE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y3r6/Xsfvsl3HksXlVYkJgHUqpQGfICxg3x9f8Zw1qM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BSltHzEwDjFN4du9rDHAPvl22atlcTioEtt+gC5L1tk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0arGXjSN0006UnXbrWsGqhvBair569DeFDUME3Df3rA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s/DumaMad08S+PBUUcrS+v42K0z8HgcdiQtrFAEu2Qs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EzJ8Y8N0OQBTlnvrK82PdevDNZZO4E6CNgYVu8Cj6Ks=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VA4vr8jBPI5QdiPrULzzZjBMIUbG3V7Slg5zm0bFcKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YAOvEB2ZLtq9LQiFViBHWaxxWVVonC2rNYj9tN9s3L0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hgaHMo9aAGS+nBwvqnTjZO+YkiQPY1c1XcIYeaYKHyI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YvaoLt3ZpH0atB0tNzwMjpoxRYJXl0DqSjisMJiGVBE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EMmW6CptFsiLoPOi5/uAJQ2FmeLg6mCpuVLLrRWk7Mc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1jQsNMarSnarlYmXEuoFokeBMg/090qUD9wqo1Zn8Gs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hupXNKhRpJxpyDAAP1TgJ5JMZh9lhbMk6s7D7dMS3C8=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json
new file mode 100644
index 000000000..2f8b991cf
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json
@@ -0,0 +1,1934 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimal",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Decimal. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimal": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimal": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedDecimal": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDecimal": {
+                  "$numberDecimal": "2"
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimal": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedDecimal": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedDecimal": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimal",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDecimal": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rbf3AeBEv4wWFAKknqDxRW5cLNkFvbIs6iJjc6LShQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0l86Ag5OszXpa78SlOUV3K9nff5iC1p0mRXtLg9M1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hn6yuxFHodeyu7ISlhYrbSf9pTiH4TDEvbYLWjTwFO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zdf4y2etKBuIpkEU1zMwoCkCsdisfXZCh8QPamm+drY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rOQ9oMdiK5xxGH+jPzOvwVqdGGnF3+HkJXxn81s6hp4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "61aKKsE3+BJHHWYvs3xSIBvlRmKswmaOo5rygQJguUg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KuDb/GIzqDM8wv7m7m8AECiWJbae5EKKtJRugZx7kR0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Q+t8t2TmNUiCIorVr9F3AlVnX+Mpt2ZYvN+s8UGict8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJRZIpKxUgHyL83kW8cvfjkxN3z6WoNnUg+SQw+LK+k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnUsYjip8SvW0+m9mR5WWTkpK+p6uwJ6yBUAlBnFKMk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PArHlz+yPRYDycAP/PgnI/AkP8Wgmfg++Vf4UG1Bf0E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wnIh53Q3jeK8jEBe1n8kJLa89/H0BxO26ZU8SRIAs9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4F8U59gzBLGhq58PEWQk2nch+R0Va7eTUoxMneReUIA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ihKagIW3uT1dm22ROr/g5QaCpxZVj2+Fs/YSdM2Noco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EJtUOOwjkrPUi9mavYAi+Gom9Y2DuFll7aDwo4mq0M0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dIkr8dbaVRQFskAVT6B286BbcBBt1pZPEOcTZqk4ZcI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aYVAcZYkH/Tieoa1XOjE/zCy5AJcVTHjS0NG2QB7muA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sBidL6y8TenseetpioIAAtn0lK/7C8MoW4JXpVYi3z8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0Dd2klU/t4R86c2WJcJDAd57k/N7OjvYSO5Vf8KH8sw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I3jZ92WEVmZmgaIkLbuWhBxl7EM6bEjiEttgBJunArA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aGHoQMlgJoGvArjfIbc3nnkoc8SWBxcrN7hSmjMRzos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bpiWPnF/KVBQr5F6MEwc5ZZayzIRvQOLDAm4ntwOi8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tI7QVKbE6avWgDD9h4QKyFlnTxFCwd2iLySKakxNR/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XGsge0CnoaXgE3rcpKm8AEeku5QVfokS3kcI+JKV1lk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JQxlryW2Q5WOwfrjAnaZxDvC83Dg6sjRVP5zegf2WiM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YFuHKJOfoqp1iGVxoFjx7bLYgVdsN4GuUFxEgO9HJ5s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z6vUdiCR18ylKomf08uxcQHeRtmyav7/Ecvzz4av3k4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SPGo1Ib5AiP/tSllL7Z5PAypvnKdwJLzt8imfIMSEJQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "m94Nh6PFFQFLIib9Cu5LAKavhXnagSHG6F5EF8lD96I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pfEkQI98mB+gm1+JbmVurPAODMFPJ4E8DnqfVyUWbSo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DNj3OVRLbr43s0vd+rgWghOL3FqeO/60npdojC8Ry/M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kAYIQrjHVu49W8FTxyxJeiLVRWWjC9fPcBn+Hx1F+Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "aCSO7UVOpoQvu/iridarxkxV1SVxU1i9HVSYXUAeXk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Gh6hTP/yj1IKlXQ+Q69KTfMlGZjEcXoRLGbQHNFo/1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/gDgIFQ4tAlJk3GN48IS5Qa5IPmErwGk8CHxAbp6gs0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PICyimwPjxpusyKxNssOOwUotAUbygpyEtORsVGXT8g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4lu+cBHyAUvuxC6JUNyHLzHsCogGSWFFnUCkDwfQdgI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pSndkmoNUJwXjgkbkgOrT5f9nSvuoMEZOkwAN9ElRaE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tyW+D4i26QihNM5MuBM+wnt5AdWGSJaJ4X5ydc9iWTU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9Syjr8RoxUgPKr+O5rsCu07AvcebA4P8IVKyS1NVLWc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "67tPfDYnK2tmrioI51fOBG0ygajcV0pLo5+Zm/rEW7U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "y0EiPRxYTuS1eVTIaPQUQBBxwkyxNckbePvKgChwd0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NWd+2veAaeXQgR3vCvzlI4R1WW67D5YsVLdoXfdb8qg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PY5RQqKQsL2GqBBSPNOEVpojNFRX/NijCghIpxD6CZk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lcvwTyEjFlssCJtdjRpdN6oY+C7bxZY+WA+QAqzj9zg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWE7XRNylvTwO/9Fv56dNqUaQWMmESNS/GNIwgBaEI0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ijwlrUeS8nRYqK1F8kiCYF0mNDolEZS+/lJO1Lg93C8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8KzV+qYGYuIjoNj8eEpnTuHrMYuhzphl80rS6wrODuU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wDyTLjSEFF895hSQsHvmoEQVS6KIkZOtq1c9dVogm9I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SGrtPuMYCjUrfKF0Pq/thdaQzmGBMUvlwN3ORIu9tHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KySHON3hIoUk4xWcwTqk6IL0kgjzjxgMBObVIkCGvk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hBIdS9j0XJPeT4ot73ngELkpUoSixvRBvdOL9z48jY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Tx6um0q9HjS5ZvlFhvukpI6ORnyrXMWVW1OoxvgqII0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zFKlyfX5H81+d4A4J3FKn4T5JfG+OWtR06ddyX4Mxas=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cGgCDuPV7MeMMYEDpgOupqyNP4BQ4H7rBnd2QygumgM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IPaUoy98v11EoglTpJ4kBlEawoZ8y7BPwzjLYBpkvHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Pfo4Am6tOWAyZNn8G9W5HWWGC3ZWmX0igI/RRB870Ro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fnTSjd7bC1Udoq6iM7UDnHAC/lsIXSHp/Gy332qw+/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fApBgVRrTDyEumkeWs5p3ag9KB48SbU4Si0dl7Ns9rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QxudfBItgoCnUj5NXVnSmWH3HK76YtKkMmzn4lyyUYY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sSOvwhKa29Wq94bZ5jGIiJQGbG1uBrKSBfOYBz/oZeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FdaMgwwJ0NKsqmPZLC5oE+/0D74Dfpvig3LaI5yW5Fs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "sRWBy12IERN43BSZIrnBfC9+zFBUdvjTlkqIH81NGt4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/4tIRpxKhoOwnXAiFn1Z7Xmric4USOIfKvTYQXk3QTc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": {
+                "$numberInt": "1"
+              },
+              "encryptedDecimal": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Mr/laWHUijZT5VT3x2a7crb7wgd/UXOGz8jr8BVqBpM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wXVD/HSbBljko0jJcaxJ1nrzs2+pchLQqYR3vywS8SU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VDCpBYsJIxTfcI6Zgf7FTmKMxUffQv+Ys8zt5dlK76I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zYDslUwOUVNwTYkETfjceH/PU3bac9X3UuQyYJ19qK0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rAOmHSz18Jx107xpbv9fYcPOmh/KPAqge0PAtuhIRnc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BFOB1OGVUen7VsOuS0g8Ti7oDsTt2Yj/k/7ta8YAdGM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2fckE5SPs0GU+akDkUEM6mm0EtcV3WDE/sQsnTtodlk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mi9+aNjuwIvaMpSHENvKzKRAmX9cYguo2mXLvOoftHQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "K6TWn4VcWWkz/gkUkLmbtwkG7SNeABICmLDnoYJFlLU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z+2/cEtGU0Fq7QJFNGA/0y4aWAsw0ncG6X0LYRqwS3c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rrSIf+lgcNZFbbUkS9BmE045jRWBpcBJXHzfMVEFuzE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KlHL3Kyje1/LMIfgbCqw1SolxffJvvgsYBV5y77wxuA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hzJ1YBoETmYeCh352dBmG8d8Wse/bUcqojTWpWQlgsc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lSdcllDXx8MA+s0GULjDA1lQkcV0L8/aHtZ6dM2pZ2c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "HGr7JLTTA7ksAnlmjSIwwdBVvgr3fv46/FTdiCPYpos=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mMr25v1VwOEVZ8xaNUTHJCcsYqV+kwK6RzGYilxPtJ4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "129hJbziPJzNo0IoTU3bECdge0FtaPW8dm4dyNVNwYU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "doiLJ96qoo+v7NqIAZLq6BI5axV8Id8gT5vyJ1ZZ0PM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cW/Lcul3xYmfyvI/0x/+ybN78aQmBK1XIGs1EEU09N8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1aVIwzu9N5EJV9yEES+/g6hOTH7cA2NTcLIc59cu0wU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kw5tyl7Ew0r1wFyrN1mB9FiVW2hK2BxxxUuJDNWjyjQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ADAY2YBrm6RJBDY/eLLcfNxmSJku+mefz74gH66oyco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8gkqB1LojzPrstpFG7RHYmWxXpIlPDTqWnNsXH7XDRU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "TESfVQMDQjfTZmHmUeYUE2XrokJ6CcrsKx/GmypGjOw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qFM+HFVQ539S0Ouynd1fBHoemFxtU9PRxE5+Dq7Ljy4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jPiFgUZteSmOg4wf3bsEKCZzcnxmMoILsgp/GaZD+dM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YaWUgJhYgPNN7TkFK16H8SsQS226JguaVhOIQxZwQNQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x90/Qk3AgyaFsvWf2KUCu5XF3j76WFSjt/GrnG01060=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZGWybWL/xlEdMYRFCZDUoz10sywTf7U/7wufsb78lH0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8l4ganN66jIcdxfHAdYLaym/mdzUUQ8TViw3MDRySPc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c8p5XEGTqxqvRGVlR+nkxw9uUdoqDqTB0jlYQ361qMA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1ZGFLlpQBcU3zIUg8MmgWwFKVz/SaA7eSYFrfe3Hb70=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "34529174M77rHr3Ftn9r8jU4a5ztYtyVhMn1wryZSkU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YkQ4pxFWzc49MS0vZM6S8mNo4wAwo21rePBeF3C+9mI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MhOf4mYY00KKVhptOcXf0bXB7WfuuM801MRJg4vXPgc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7pbbD8ihNIYIBJ3tAUPGzHpFPpIeCTAk5L88qCB0/9w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "C9Q5PoNJTQo6pmNzXEEXUEqH22//UUWY1gqILcIywec=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "AqGVk1QjDNDLYWGRBX/nv9QdGR2SEgXZEhF0EWBAiSE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/sGI3VCbJUKATULJmhTayPOeVW+5MjWSvVCqS77sRbU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yOtbL0ih7gsuoxVtRrACMz+4N5uo7jIR7zzmtih2Beo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uA6dkb2Iyg9Su8UNDvZzkPx33kPZtWr/CCuEY+XgzUM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1DoSFPdHIplqZk+DyWAmEPckWwXw/GdB25NLmzeEZhk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OfDVS0T3ZuIXI/LNbTp6C9UbPIWLKiMy6Wx+9tqNl+g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3PZjHXbmG6GtPz+iapKtQ3yY4PoFFgjIy+fV2xQv1YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kaoLN0BoBWsmqE7kKkJQejATmLShd8qffcAmlhsxsGY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vpiw9KgQdegGmp7IJnSGX2miujRLU0xzs0ITTqbPW7c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NuXFf7xGUefYjIUTuMxNUTCfVHrF8oL0AT7dPv5Plk4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8Tz53LxtfEBJ9eR+d2690kwNsqPV6XyKo2PlqZCbUrc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "e6zsOmHSyV8tyQtSX6BSwui6wK9v1xG3giY/IILJQ2w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2fedFMCxa2DzmIpfbDKGXhQg0PPwbUv6vIWdwwlvhms=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yEJKMFnWXTC8tJUfzCInzQRByNEPjHxpw4L4m8No91Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YbFuWwOiFuQyOzIJXDbOkCWC2DyrG+248TBuVCa1pXU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "w7IkwGdrguwDrar5+w0Z3va5wXyZ4VXJkDMISyRjPGo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YmJUoILTRJPhyIyWyXJTsQ6KSZHHbEpwPVup6Ldm/Ko=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FvMjcwVZJmfh6FP/yBg2wgskK+KHD8YVUY6WtrE8xbg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "h4HCtD4HyYz0nci49IVAa10Z4NJD/FHnRMV4sRX6qro=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nC7BpXCmym+a0Is2kReM9cYN2M1Eh5rVo8fjms14Oiw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1qtVWaeVo649ZZZtN8gXbwLgMWGLhz8beODbvru0I7Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Ej+mC0QFyMNIiSjR939S+iGBm7dm+1xObu5IcF/OpbU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UQ8LbUG3cMegbr9yKfKanAPQE1EfPkFciVDrNqZ5GHY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4iI3mXIDjnX+ralk1HhJY43mZx2uTJM7hsv9MQzTX7E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0WQCcs3rvsasgohERHHCaBM4Iy6yomS4qJ5To3/yYiw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qDCTVPoue1/DOAGNAlUstdA9Sid8MgEY4e5EzHcVHRk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9F9Mus0UnlzHb8E8ImxgXtz6SU98YXD0JqswOKw/Bzs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pctHpHKVBBcsahQ6TNh6/1V1ZrqOtKSAPtATV6BJqh0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vfR3C/4cPkVdxtNaqtF/v635ONbhTf5WbwJM6s4EXNE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ejP43xUBIex6szDcqExAFpx1IE/Ksi5ywJ84GKDFRrs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jbP4AWYd3S2f3ejmMG7dS5IbrFol48UUoT+ve3JLN6U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CiDifI7958sUjNqJUBQULeyF7x0Up3loPWvYKw9uAuw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "e2dQFsiHqd2BFHNhlSxocjd+cPs4wkcUW/CnCz4KNuM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PJFckVmzBipqaEqsuP2mkjhJE4qhw36NhfQ9DcOHyEU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "S3MeuJhET/B8VcfZYDR9fvX0nscDj416jdDekhmK11s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CGVHZRXpuNtQviDB2Kj03Q8uvs4w3RwTgV847R7GwPw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yUGgmgyLrxbEpDVy89XN3c2cmFpZXWWmuJ/35zVZ+Jw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "inb6Q97mL1a9onfNTT8v9wsoi/fz7KXKq3p8j90AU9c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CCyYx/4npq9xGO1lsCo8ZJhFO9/tN7DB+/DTE778rYg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "LNnYw4fwbiAZu0kBdAHPEm/OFnreS+oArdB5O/l/I98=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "P006SxmUS/RjiQJVYPdMFnNo3827GIEmSzagggkg05Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "oyvwY+WsnYV6UHuPki1o0ILJ2jN4uyXf9yaUNtZJyBA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "36Lk3RHWh1wmtCWC/Yj6jNIo17U5y6SofAgQjzjVxD8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vOOo8FqeHnuO9mqOYjIb4vgwIwVyXZ5Y+bY5d9tGFUM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bJiDJjwQRNxqxlGjRm5lLziFhcfTDCnQ/qU1V85qcRg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2Qgrm1n0wUELAQnpkEiIHB856yv76q8jLbpiucetcm0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "5ciPOYxTK0WDwwYyfs7yiVymwtYQXDELLxmM4JLl4/o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "31dC2WUSIOKQc4jwT6PikfeYTwi80mTlh7P31T5KNQU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YluTV2Mu53EGCKLcWfHZb0BM/IPW2xJdG3vYlDMEsM4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dh/8lGo2Ek6KukSwutH6Q35iy8TgV0FN0SJqe0ZVHN8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EVw6HpIs3BKen2qY2gz4y5dw1JpXilfh07msZfQqJpc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FYolLla9L8EZMROEdWetozroU40Dnmwwx2jIMrr7c1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "8M6k4QIutSIj6CM41vvkQtuFsaGrjoR9SZJVSLbfGKQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9LM0VoddDNHway442MqY+Z7vohB2UHau/cddshhzf40=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "66i8Ytco4Yq/FMl6pIRZazz3CZlu8fO2OI6Pne0pvHU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2a/HgX+MjZxjXtSvHgF1yEpHMJBkl8Caee8XrJtn0WM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "frhBM662c4ZVG7mWP8K/HhRjd01lydW/cPcHnDjifqc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6k1T7Q1t668PBqv6fwpVnT1HWh7Am5LtbKvwPJKcpGU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UlJ5Edfusp8S/Pyhw6KTglIejmbr1HO0zUeHn/qFETA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jsxsB+1ECB3assUdoC333do9tYH+LglHmVSJHy4N8Hg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2nzIQxGYF7j3bGsIesECEOqhObKs/9ywknPHeJ3yges=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xJYKtuWrX90JrJVoYtnwP7Ce59XQGFYoalxpNfBXEH0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NLI5lriBTleGCELcHBtNnmnvwSRkHHaLOX4cKboMgTw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hUOQV0RmE5aJdJww1AR9rirJG4zOYPo+6cCkgn/BGvQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "h4G2Of76AgxcUziBwCyH+ayMOpdBWzg4yFrTfehSC2c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VuamM75RzGfQpj2/Y1jSVuQLrhy6OAwlZxjuQLB/9Ss=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kn9+hLq7hvw02xr9vrplOCDXKBTuFhfbX7d5v/l85Pg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fAiGqKyLZpGngBYFbtYUYt8LUrJ49vYafiboifTDjxs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BxRILymgfVJCczqjUIWXcfrfSgrrYkxTM5VTg0HkZLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CrFY/PzfPU2zsFkGLu/dI6mEeizZzCR+uYgjZBAHro0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "AEbrIuwvXLTtYgMjOqnGQ8y8axUn5Ukrn7UZRSyfQVw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ouWeVH3PEFg+dKWlXc6BmqirJOaVWjJbMzZbCsce4dA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+hd6xFB+EG+kVP7WH4uMd1CLaWMnt5xJRaY/Guuga9Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zmpGalfAOL3gmcUMJYcLYIRT/2VDO/1Dw4KdYZoNcng=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2PbHAoM/46J2UIZ/vyksKzmVVfxA7YUyIxWeL/N/vBk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7fD9x+zk5MVFesb59Klqiwwmve7P5ON/5COURXj5smE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tlrNQ4jaq051iaWonuv1sSrYhKkL1LtNZuHsvATha3s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fBodm28iClNpvlRyVq0dOdXQ08S7/N3aDwid+PdWvRo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "O+/nnRqT3Zv7yMMGug8GhKHaWy6u7BfRGtZoj0sdN1c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "5AZZ/RTMY4Photnm/cpXZr/HnFRi3eljacMsipkJLHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "oFVyo/kgoMxBIk2VE52ySSimeyU+Gr0EfCwapXnTpKA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Z8v59DfcnviA0mzvnUk+URVO0UuqAWvtarEgJva/n1c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "P64GOntZ+zBJEHkigoh9FSxSO+rJTqR20z5aiGQ9an4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xMbSuDPfWuO/Dm7wuVl06GnzG9uzTlJJX9vFy7boGlY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kXPB19mRClxdH2UsHwlttS6lLU2uHvzuZgZz7kC45jU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NDVjVYXAw4k0w4tFzvs7QDq39aaU3HQor4I2XMKKnCk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uKw/+ErVfpTO1dGUfd3T/eWfZW3nUxXCdBGdjvHtZ88=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "av0uxEzWkizYWm0QUM/MN1hLibnxPvCWJKwjOV4yVQY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ERwUC47dvgOBzIsEESMIioLYbFOxOe8PtJTnmDkKuHM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2gseKlG5Le12fS/vj4eaED4lturF16kAgJ1TpW3HxEE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7Cvg0Y3j/5i2F1TeXxlMmU7xwif5dCmwkZAOrVC5K2Y=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json
new file mode 100644
index 000000000..a3e605d1b
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json
@@ -0,0 +1,590 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDecimal": "0.0"
+          },
+          "max": {
+            "$numberDecimal": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DecimalPrecision. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$gt": {
+                      "$numberDecimal": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedDecimalPrecision": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": {
+                "$numberInt": "1"
+              },
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mVZb+Ra0EYjQ4Zrh9X//E2T8MRj7NMqm5GUJXhRrBEI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MgwakFvPyBlwqFTbhWUF79URJQWFoJTGotlEVSPPUsQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DyBERpMSD5lEM5Nhpcn4WGgxgn/mkUVJp+PYSLX5jsE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I43iazc0xj1WVbYB/V+uTL/tughN1bBlxh1iypBnNsA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wjOBa/ATMuOywFmuPgC0GF/oeLqu0Z7eK5udzkTPbis=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gRQVwiR+m+0Vg8ZDXqrQQcVnTyobwCXNaA4BCJVXtMc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WUZ6huwx0ZbLb0R00uiC9FOJzsUocUN8qE5+YRenkvQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7s79aKEuPgQcS/YPOOVcYNZvHIo7FFsWtFCrnDKXefA=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json
new file mode 100644
index 000000000..9fafc243d
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json
@@ -0,0 +1,1650 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDecimal": "0.0"
+          },
+          "max": {
+            "$numberDecimal": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "0.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gte": {
+                  "$numberDecimal": "0.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "1.0"
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$lt": {
+                  "$numberDecimal": "1.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$lte": {
+                  "$numberDecimal": "1.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$lt": {
+                  "$numberDecimal": "0.0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "200.0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be less than the range max"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "0.0"
+                },
+                "$lt": {
+                  "$numberDecimal": "2.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gte": {
+                  "$numberDecimal": "0.0"
+                },
+                "$lte": {
+                  "$numberDecimal": "200.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$in": [
+                  {
+                    "$numberDecimal": "0.0"
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Insert out of range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "-1"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "value must be greater than or equal to the minimum value"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Insert min and max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 200,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "200.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {},
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 200,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "200.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$gte": {
+                      "$numberDecimal": "0.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$gt": {
+                      "$numberDecimal": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$lt": {
+                      "$numberDecimal": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$lte": {
+                      "$numberDecimal": "1.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$lt": {
+                      "$numberDecimal": "0.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$gt": {
+                      "$numberDecimal": "200.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be less than the range max"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$gt": {
+                      "$numberDecimal": "0.0"
+                    },
+                    "$lt": {
+                      "$numberDecimal": "2.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$numberDecimal": "0.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$numberDecimal": "1.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$gte": {
+                      "$numberDecimal": "0.0"
+                    },
+                    "$lte": {
+                      "$numberDecimal": "200.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDecimalPrecision": {
+                    "$in": [
+                      {
+                        "$numberDecimal": "0.0"
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberInt": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gte": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json
new file mode 100644
index 000000000..3d7d359af
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json
@@ -0,0 +1,493 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDecimal": "0.0"
+          },
+          "max": {
+            "$numberDecimal": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DecimalPrecision. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedDecimalPrecision": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDecimalPrecision": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json
new file mode 100644
index 000000000..b1442c3a3
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json
@@ -0,0 +1,612 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDecimal": "0.0"
+          },
+          "max": {
+            "$numberDecimal": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DecimalPrecision. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDecimalPrecision": {
+                  "$numberDecimal": "2"
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedDecimalPrecision": {
+              "$numberDecimal": "1"
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedDecimalPrecision": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDecimalPrecision": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": {
+                "$numberInt": "0"
+              },
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": {
+                "$numberInt": "1"
+              },
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "V6knyt7Zq2CG3++l75UtBx2m32iGAPjHiAe439Bf02w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0OKSXELxPP85SBVwDGf3LtMEQCJ8TTkFUl/+6jlkdb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uEw0lpQtBppR3vqV9j9+NQRSBF1BzZukb8c9IhyWvxc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zVhZ7Q59O087ji49oMJvBIgeir2oqvUpnh4p53GcTow=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dowrzKs+qJhRMZyKDbhjXbuX43FbmUKOaw9I8YlOZDw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ep5B6cska6THLIF7Mn3tn3RvV9EiwLSt0eZM/CLRUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "URNp/YmmDh5wIZUfAzzgPyJeMNiVx9PMsz52DZRujGY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wlM4IAQhhKQEzoVqS8b1Ddd50GB95OFb9LnzOwyjCP4=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json
new file mode 100644
index 000000000..3b8202ff8
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json
@@ -0,0 +1,577 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDecimal": "0.0"
+          },
+          "max": {
+            "$numberDecimal": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DecimalPrecision. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedDecimalPrecision": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CvoJAAADcGF5bG9hZADKCQAABGcAjgkAAAMwAH0AAAAFZAAgAAAAAHdJ2Vnb4MMzqVYVssjSdDy8XU4GVzMTfGifGETgQ2mYBXMAIAAAAAD7cFfKJGIXo6PjyeX2ria02CckW7dWFDoY/3FyBdm1NQVjACAAAAAAqZO+/+gRWlPaMOvuiXizSmBe7lp1VWg1vJ4UmW8o3bQAAzEAfQAAAAVkACAAAAAAlmvfDrZoydUet4eCVMq7z6a58Ea+1HLJOWxN5lNcrWEFcwAgAAAAAEBo5AWZyC41b9ayjWNQSL4iYEAIwR/JG+ssN8bdoK9RBWMAIAAAAAD4FTKJ6CTzKBAyAwZCLUoDEfnZTRZmhF1q/2hnDzmG9gADMgB9AAAABWQAIAAAAABbiLaoxAA6rinMJw1hC8ZUiq6UU1AQaPFn/py/Y06WuQVzACAAAAAAhtDasFkvYE7SCNu1je/hxdE9TJtAvvH3NtdEbKzNbCUFYwAgAAAAAHHy019aPatHTST+0wGsmukUcsQNQj6KpoS9b7iGeThAAAMzAH0AAAAFZAAgAAAAALORWwSr+tYNxcil2KIGSbNhTHvcPbdj+rLVQNx21S/KBXMAIAAAAAD6diZBkPEJ1cQy06LAxdbNK8Nlxbb44fH4Wk3Y3260nQVjACAAAAAAvUc1q7pyhjU0ilgmwiKkHIY3V4/LxO+Y2uT7eSpBOs8AAzQAfQAAAAVkACAAAAAAG5XMK96PjClNlUvg82j4pMY1YxsznZfj4uNweD394FoFcwAgAAAAAKHgQLdGJHkrfFg9nB93Ac+3VgBw6aU44MTkKIQ91dZoBWMAIAAAAACtbNc1DCoUUyzlkrYmJi4NlwOqLYmb6au4pDc8clXVXwADNQB9AAAABWQAIAAAAAA6M++b9I0YFemmWBAWAE3glu2Ah3Ta1FBxAQEIWS0toAVzACAAAAAANXYTqPf1Y6X3Ns6YQIX0C3FKCyWUo+Kk+fNcQvc0WSoFYwAgAAAAAAaqju6Dv8wqXxcsIbP67V1QGaD5kNTFofZ9Zuf1LGnKAAM2AH0AAAAFZAAgAAAAAKl8bV1riH/uyJ+X0HHd3+18k2cJl2dQFXCdoagutFcaBXMAIAAAAABm8F2Ew9f0VOABdcF+lP0Bi+zWvEUPniWgrxPq/Sx3uwVjACAAAAAAQd2pWVqlmmLg8m8xbs7yLewmR0Z6UQgXofbCsMHaGSoAAzcAfQAAAAVkACAAAAAAsYZD8JEP6kYsPncFnNZwJxhu4YtUTKPNcjHtv67H+rYFcwAgAAAAAI4LqZcRkvbs/2F62Flu0pixNcor4WmBD0DHGaf039wLBWMAIAAAAAAqzpfyBpr4Ano+nFWJyyTuIJelJgiRDnMHQqdeqV8JaAADOAB9AAAABWQAIAAAAAC0vdAi+dmoIXvZ5LqUqvyKV9/tHqSI2SWiSJO5pTnA2wVzACAAAAAAS2qvf9fvfVUH5WtsVxjxmskpGjYTQV34LwvQQw1y9wIFYwAgAAAAAFhNY4qwNntyA+GIoNHZsTkIUbPgy4TBlvNnTPjp4bMFAAM5AH0AAAAFZAAgAAAAAH31lb/srBcrOXkzddCwAnclsR5/3QijEVgECs2JjOWBBXMAIAAAAABg7+prDT73YcCvLE5QbuIrqGcjLc5pQD2Miq0d29yrxgVjACAAAAAAFKqAqXG/ktejFQ7fM2aobO2VmEvZLXnRaJH97Jy/sJYAAzEwAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzExAH0AAAAFZAAgAAAAAFdthRhe2Q8CvxGIhjTJZv0Lk97GkHciTPxZ/mckLoNaBXMAIAAAAAAqOxsAr23LOVB0DIHbPf9UDJJRFXY2YoKbjhRqw5psbQVjACAAAAAA7ty+Nif6KjS3v1zWKaHX9n4Zj3XC4ajuCduKNIYr3l8AAzEyAH0AAAAFZAAgAAAAAMWymwwbvIeMqmnKWWifUqoCxOsdpnonM2qdLPyjqJO/BXMAIAAAAAB6IDmmpUhBD2zpRj8/y/kmOSXcjuIU14sNh6GKSsg2uwVjACAAAAAABSWO0Ii+NGcsHZQ9MR5EjPXVKeXlI4FQ1pcxeKDiuooAAzEzAH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzE0AH0AAAAFZAAgAAAAAJaRYmo8zqI2BEUzdSwp4tVRpPmVWsfydkYN3UHh6TMuBXMAIAAAAAAeD6mDnQeLlbC9i0sVgE8+RH6y+e94OJQ0tJ0PvblVSgVjACAAAAAAKUhYSt4nvvUfbNgPJ2E79SciVZ0ZzbzoZ2nKr4ewNLsAAzE1AH0AAAAFZAAgAAAAAAZZ538coNPwyRjhEwr5P8Xw32oWOJF+R+nfCGgy2qO3BXMAIAAAAACOPLnJlKwGNPDBReRKnHfteq0wFb3ezhrc7BVXs8RUHwVjACAAAAAAzCICkPZAkfTiD0MUt155dIPgLJ4/e0qFTM2FR0U261YAAzE2AH0AAAAFZAAgAAAAAFH9l9GGA1I52atJV5jNUf1lx8jBjoEoVoME97v5GFJiBXMAIAAAAAC1qH3Kd78Dr9NGbw7y9D/XYBwv5h1LLO8la5OU7g8UkQVjACAAAAAAn27H0Mpwatgc1R/4nXSRjsG2PzB0ol5YR9f3mCb2y/0AAzE3AH0AAAAFZAAgAAAAADtbVEI2tdkrowEMdkacD2w0Y3T3Ofi7PH6HmA6sP0c/BXMAIAAAAADuBSROnZHA+NgUPH8d0LnWFiDsM2bY8bzjC1+elSsIygVjACAAAAAAMinHEu4wkbeOpdZbXQ94q5o5pIEubqXUDrTRYOGmJC0AAzE4AH0AAAAFZAAgAAAAAAh3WpeMVlikPFYj9hLj+fmIqVt6omCSF75W3TPExyWpBXMAIAAAAAAsQkRmwqeVj2gGE03orb6PtrIzDt6dDU3hgSQi8E2wKgVjACAAAAAAvlZo8Qj3eAdxzZxN5sHKhxi+a9Npj7cZC5+pE6qrOawAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mVZb+Ra0EYjQ4Zrh9X//E2T8MRj7NMqm5GUJXhRrBEI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MgwakFvPyBlwqFTbhWUF79URJQWFoJTGotlEVSPPUsQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DyBERpMSD5lEM5Nhpcn4WGgxgn/mkUVJp+PYSLX5jsE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I43iazc0xj1WVbYB/V+uTL/tughN1bBlxh1iypBnNsA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wjOBa/ATMuOywFmuPgC0GF/oeLqu0Z7eK5udzkTPbis=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gRQVwiR+m+0Vg8ZDXqrQQcVnTyobwCXNaA4BCJVXtMc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WUZ6huwx0ZbLb0R00uiC9FOJzsUocUN8qE5+YRenkvQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7s79aKEuPgQcS/YPOOVcYNZvHIo7FFsWtFCrnDKXefA=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json
new file mode 100644
index 000000000..3dc6631c6
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json
@@ -0,0 +1,612 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDecimal": "0.0"
+          },
+          "max": {
+            "$numberDecimal": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DecimalPrecision. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$numberDecimal": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedDecimalPrecision": {
+                "$gt": {
+                  "$numberDecimal": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDecimalPrecision": {
+                  "$numberDecimal": "2"
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDecimalPrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedDecimalPrecision": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedDecimalPrecision": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDecimalPrecision",
+                        "bsonType": "decimal",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDecimal": "0.0"
+                          },
+                          "max": {
+                            "$numberDecimal": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDecimalPrecision": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDecimalPrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "V6knyt7Zq2CG3++l75UtBx2m32iGAPjHiAe439Bf02w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0OKSXELxPP85SBVwDGf3LtMEQCJ8TTkFUl/+6jlkdb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uEw0lpQtBppR3vqV9j9+NQRSBF1BzZukb8c9IhyWvxc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zVhZ7Q59O087ji49oMJvBIgeir2oqvUpnh4p53GcTow=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dowrzKs+qJhRMZyKDbhjXbuX43FbmUKOaw9I8YlOZDw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ep5B6cska6THLIF7Mn3tn3RvV9EiwLSt0eZM/CLRUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "URNp/YmmDh5wIZUfAzzgPyJeMNiVx9PMsz52DZRujGY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wlM4IAQhhKQEzoVqS8b1Ddd50GB95OFb9LnzOwyjCP4=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json
new file mode 100644
index 000000000..3d54be3d1
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json
@@ -0,0 +1,1138 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDouble",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Double. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$gt": {
+                      "$numberDouble": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedDouble": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "Cq8kAAADcGF5bG9hZAB/JAAABGcAQyQAAAMwAH0AAAAFZAAgAAAAAHgYoMGjEE6fAlAhICv0+doHcVX8CmMVxyq7+jlyGrvmBXMAIAAAAAC/5MQZgTHuIr/O5Z3mXPvqrom5JTQ8IeSpQGhO9sB+8gVjACAAAAAAPMgD8Rqnd94atKnMyPjlTwthUQ710MKJVqgtwNXLFWwAAzEAfQAAAAVkACAAAAAA2kiWNvEc4zunJ1jzvuClFC9hjZMYruKCqAaxq+oY8EAFcwAgAAAAACofIS72Cm6s866UCk+evTH3CvKBj/uZd72sAL608rzTBWMAIAAAAAB7NkTFgsBuPIyxW5KtYZD4uxdgRynoAUwA2RDj3qZNdwADMgB9AAAABWQAIAAAAABkfoBGmU3hjYBvQbjNW19kfXneBQsQQPRfUL3UAwI2cAVzACAAAAAAUpK2BUOqX/DGdX5YJniEZMWkofxHqeAbXceEGJxhp8AFYwAgAAAAAENNdd+fMV7VQzshj6RdvsxqDHYkPDxggdUHw3JbmFBeAAMzAH0AAAAFZAAgAAAAAFNprhQ3ZwIcYbuzLolAT5n/vc14P9kUUQComDu6eFyKBXMAIAAAAAAcx9z9pk32YbPV/sfPZl9ALIEVsqoLXgqWLVK/tP+heAVjACAAAAAA3eqduo9CWE5BePqBq7KCh5++QqXnyjCwybB15Zoeiu4AAzQAfQAAAAVkACAAAAAAODI+pB2pCuB+YmNEUAgtMfNdt3DmSkrJ96gRzLphgb8FcwAgAAAAAAT7dewFDxUDECQ3zVq75/cUN4IP+zsqhkP5+czUwlJIBWMAIAAAAABYcCJA2jocGQiF/vZ9VDEktoK015OqfY64yZhmNPs9GQADNQB9AAAABWQAIAAAAACNAk+yTZ4Ewk1EnotQK8O3h1gg9I7pr9q2+4po1iJVgAVzACAAAAAAUj/LesmtEsgqYVzMJ67umVA11hJTdDXwbxDoQ71vWyUFYwAgAAAAAG32XaKjEO9YTSLMnDR5eiaUpgBQz0n4M3VpBqhWTaEnAAM2AH0AAAAFZAAgAAAAAD/FIrGYFDjyYmVb7oTMVwweWP7A6F9LnyIuNO4MjBnXBXMAIAAAAACIZgJCQRZu7NhuNMyOqCn1tf+DfU1qm10TPCfj5JYV3wVjACAAAAAAZCaO06/DjOBjNrTxB8jdxM7X4XvNu9QTa2Y00kZJwgEAAzcAfQAAAAVkACAAAAAAciRW40ORJLVwchOEpz87Svb+5toAFM6LxDWv928ECwQFcwAgAAAAAN0dipyESIkszfjRzdDi8kAGaa2Hf4wrPAtiWwboZLuxBWMAIAAAAADhvKHhF7zfNRnG8QfiIlKycV6L6iGxbGNKkHligA9rAgADOAB9AAAABWQAIAAAAACZqAyCzYQupJ95mrBJX54yIz9VY7I0WrxpNYElCI4dTQVzACAAAAAA/eyJb6d1xfE+jJlVXMTD3HS/NEYENPVKAuj56Dr2dSEFYwAgAAAAAMfcJKj77c6y/RBQ5hb5LSNdvbYvCAHR59KLnbmxj1gAAAM5AH0AAAAFZAAgAAAAAI5bm3YO0Xgf0VT+qjVTTfvckecM3Cwqj7DTKZXf8/NXBXMAIAAAAAD/m+h8fBhWaHm6Ykuz0WX1xL4Eme3ErLObyEVJf8NCywVjACAAAAAAiGdTXD22l1zDxHeF4NXUTiBnNTsdpzJRwM6riTPuOogAAzEwAH0AAAAFZAAgAAAAANqo4+p6qdtCzcB4BX1wQ6llU7eFBnuu4MtZwp4B6mDlBXMAIAAAAAAGiz+VaukMZ+6IH4jtn4KWWdKK4/W+O+gRioQDrfzpMgVjACAAAAAAl/wlBjSJW/hKkll8HSBCGw4Ce1pJ5rZuhVE09hKq4jQAAzExAH0AAAAFZAAgAAAAAPrFXmHP2Y4YAm7b/aqsdn/DPoDkv7B8egWkfe23XsM1BXMAIAAAAAAGhwpKAr7skeqHm3oseSbO7qKNhmYsuUrECBxJ5k+D2AVjACAAAAAAKSsxERy2OBhb5MiH9/H2BET2oeU6yVihiAoWi/16FroAAzEyAH0AAAAFZAAgAAAAABzjYxwAjXxXc0Uxv18rH8I3my0Aguow0kTwKyxbrm+cBXMAIAAAAADVbqJVr6IdokuhXkEtXF0C2gINLiAjMVN20lE20Vmp2QVjACAAAAAACJ+VAwl9X88mjC76yzkWeL4K6AamNYjbNkpS9B6fQE4AAzEzAH0AAAAFZAAgAAAAAFMm2feF2fFCm/UC6AfIyepX/xJDSmnnolQIBnHcPmb5BXMAIAAAAABLI11kFrQoaNVZFmq/38aRNImPOjdJh0Lo6irI8M/AaAVjACAAAAAAZFgYh4nV8YN+/AAqe/QhKDkNBPg8KraCG7y3bOzhPV4AAzE0AH0AAAAFZAAgAAAAAJvXB3KyNiNtQko4SSzo/9b2qmM2zU9CQTTDfLSBWMgRBXMAIAAAAAAvjuVP7KsLRDeqVqRziTKpBrjVyqKiIbO9Gw8Wl2wFTAVjACAAAAAARuBn3JdQ8so7Gy0XVH0CtlvtRoJWhSrJP6eRIqbyWh8AAzE1AH0AAAAFZAAgAAAAAPGdcxDiid8z8XYnfdDivNMYVPgBKdGOUw6UStU+48CdBXMAIAAAAAARj6g1Ap0eEfuCZ4X2TsEw+Djrhto3fA5nLwPaY0vCTgVjACAAAAAATxLY6SkcLPaoOBJpQsggEqoxgJgiY9seP3fBQM05PckAAzE2AH0AAAAFZAAgAAAAAP5rGPrYGt3aKob5f/ldP0qrW7bmWvqnKY4QwdDWz400BXMAIAAAAADTQkW2ymaaf/bhteOOGmSrIR97bAnJx+yN3yMj1bTeewVjACAAAAAA6O+wIMt3xMITuCxVrqOCNBPX5F122G+/Is+EYkzUvVYAAzE3AH0AAAAFZAAgAAAAAAlz6wJze5UkIxKpJOZFGCOf3v2KByWyI6NB6JM9wNcBBXMAIAAAAABUC7P/neUIHHoZtq0jFVBHY75tSFYr1Y5S16YN5XxC1QVjACAAAAAANv97jMd9JmZ7lMeCzK7jaZHZYsZJNl6N9g9WXzd2om0AAzE4AH0AAAAFZAAgAAAAAFJ8AtHcjia/9Y5pLEc3qVgH5xKiXw12G9Kn2A1EY8McBXMAIAAAAAAxe7Bdw7eUSBk/oAawa7uicTEDgXLymRNhBy1LAxhDvwVjACAAAAAAtOUZ2NeUWwESpq95O92dhqYBt8RtFnjT43E7k9mQF3oAAzE5AH0AAAAFZAAgAAAAAO8uwQUaKFb6vqR3Sv3Wn4QAonC2exOC9lGG1juqP5DtBXMAIAAAAABZf1KyJgQg8/Rf5c02DgDK2aQu0rNCOvaL60ohDHyY+gVjACAAAAAA5nAWj1Ek8p0MLYZEB3yoVFDfBYZ+/ZpIo71u+W9hprcAAzIwAH0AAAAFZAAgAAAAAE8YtqyRsGCeiR6hhiyisR/hccmK4nZqIMzO4lUBmEFzBXMAIAAAAAC1UYOSKqAeG1UJiKjWFVskRhuFKpj9Ezy+lICZvFlN5AVjACAAAAAA37oP30mTzVftI2FL9Uwyls/jqLqbmRDQk7p7nlx44uYAAzIxAH0AAAAFZAAgAAAAAPhCrMausDx1QUIEqp9rUdRKyM6a9AAx7jQ3ILIu8wNIBXMAIAAAAACmH8lotGCiF2q9VQxhsS+7LAZv79VUAsOUALaGxE/EpAVjACAAAAAAhVIkl8p19VZ0gpg32s++Jda3qsVSVB5tV4CKrtjhE3IAAzIyAH0AAAAFZAAgAAAAAOBi/GAYFcstMSJPgp3VkMiuuUUCrZytvqYaU8dwm8v2BXMAIAAAAACEZSZVyD3pKzGlbdwlYmWQhHHTV5SnNLknl2Gw8IaUTQVjACAAAAAAriBex2kK//RPhyVpCYJDBng4l5w8jD3m8BF7dVAP0p8AAzIzAH0AAAAFZAAgAAAAAIQuup+YGfH3mflzWopN8J1X8o8a0d9CSGIvrA5HOzraBXMAIAAAAADYvNLURXsC2ITMqK14LABQBI+hZZ5wNf24JMcKLW+84AVjACAAAAAAGeUzdG2kQrx5XypXJezZmPVzMYuqYZw7Bhbl4EPT0SMAAzI0AH0AAAAFZAAgAAAAAKsh0ADyOnVocFrOrf6MpTrNvAj8iaiE923DPryu124gBXMAIAAAAADg24a8NVE1GyScc6tmnTbmu5ulzO+896fE92lN08MeswVjACAAAAAAbO+DEBY3STVMQN7CbxmHDUBYrDR+80e797u/VmiK4vcAAzI1AH0AAAAFZAAgAAAAAKkVC2Y6HtRmv72tDnPUSjJBvse7SxLqnr09/Uuj9sVVBXMAIAAAAABYNFUkH7ylPMN+Bc3HWX1e0flGYNbtJNCY9SltJCW/UAVjACAAAAAAHlE3RLKcXpXto7Mr8nRgzEsmhjfGh4vcgPxashCSMg4AAzI2AH0AAAAFZAAgAAAAADDggcwcb/Yn1Kk39sOHsv7BO/MfP3m/AJzjGH506Wf9BXMAIAAAAAAYZIsdjICS0+BDyRUPnrSAZfPrwtuMaEDEn0/ijLNQmAVjACAAAAAA1c/sy3255NofBQrnBNSmVkSzMgsGPaaOUJShddVrnuQAAzI3AH0AAAAFZAAgAAAAAEWY7dEUOJBgjOoWVht1wLehsWAzB3rSOBtLgTuM2HC8BXMAIAAAAAAAoswiHRROurjwUW8u8D5EUT+67yvrgpB/j6PzBDAfVwVjACAAAAAALBvQumG8m7/bzJjGWN2cHSAncdN8jMtOSmEhEhGom24AAzI4AH0AAAAFZAAgAAAAAPZaapeAUUFPA7JTCMOWHJa9lnPFh0/gXfAPjA1ezm4ZBXMAIAAAAACmJvLY2nivw7/b3DOKH/X7bBXjJwoowqb1GtEFO3OYgAVjACAAAAAAGCDHuUJusGHKQ+r9nrFChmUUsRcqZKPGsRiLSk5gbFcAAzI5AH0AAAAFZAAgAAAAAK00u6jadxCZAiA+fTsPVDsnW5p5LCr4+kZZZOTDuZlfBXMAIAAAAAAote4zTEYMDgaaQbAdN8Dzv93ljPLdGjJzvnRn3KXgtQVjACAAAAAApZ6l+OrocOqgFek7WOqOP9JruTWZ+iW+5zdL3DZwzhkAAzMwAH0AAAAFZAAgAAAAAFbgabdyymiEVYYwtJSWa7lfl/oYuj/SukzJeDOR6wPVBXMAIAAAAADAFGFjS1vPbN6mQEhkDYTD6V2V23Ys9gUEUMGNvMPkaAVjACAAAAAAeICKly5Xtwmfd4JFD+5e1UWpu4V3KoRim7jeBICDs+UAAzMxAH0AAAAFZAAgAAAAABNMR6UBv2E627CqLtQ/eDYx7OEwQ7JrR4mSHFa1N8tLBXMAIAAAAAAxH4gucI4UmNVB7625C6hFSVCuIpJO3lusJlPuL8H5EQVjACAAAAAA0/uh1hrAlGGna/njCVaCqBwubxkifzF0zjCDQrIJOtUAAzMyAH0AAAAFZAAgAAAAAG8cd6WBneNunlqrQ2EmNf35W7OGObGq9WL4ePX+LUDmBXMAIAAAAAAjJ2+sX87NSis9hBsgb1QprVRnO7Bf+GObCGoUqyPE4wVjACAAAAAAAoJ4Ufdq45T9Aun5FupHlaBCIUsmUn6dXgV9KorpFikAAzMzAH0AAAAFZAAgAAAAAFWOUGkUpy8yf6gB3dio/aOfRKh7XuhvsUj48iESFJrGBXMAIAAAAAAY7sCDMcrUXvNuL6dO0m11WyijzXZvPIcOKob6IpC4PQVjACAAAAAAO/QFjczoznH95Iu0YEVMsU1GA1yxSGL8bcwSweNzAtkAAzM0AH0AAAAFZAAgAAAAAGUrIdKxOihwNmo6B+aG+Ag1qa0+iqdksHOjQj+Oy9bZBXMAIAAAAABwa5dbI2KmzBDNBTQBEkjZv4sPaeRkRNejcjdVymRFKQVjACAAAAAAUtdJucZoQvvPJiy65RonQrxBCcvtfHslpbgLbtWirCYAAzM1AH0AAAAFZAAgAAAAAOx89xV/hRk64/CkM9N2EMK6aldII0c8smdcsZ46NbP8BXMAIAAAAADBF6tfQ+7q9kTuLyuyrSnDgmrdmrXkdhl980i1KHuGHgVjACAAAAAAVc5njbLX1afpsuG662U/OBo4LanEk06lKbQtd95fswgAAzM2AH0AAAAFZAAgAAAAAMkN0L1oQWXhjwn9rAdudcYeN8/5VdCKU8cmDt7BokjsBXMAIAAAAAAT62pGXoRwExe9uvgYOI0hg5tOxilrWfoEmT0SMglWJwVjACAAAAAAhNc5ovIaxgtS856ZBfG+cAcHAz+3ewzB9C6zZoaggj4AAzM3AH0AAAAFZAAgAAAAANxfa4xCoaaB7k1C1RoH1LBhsCbN2yEq15BT9b+iqEC4BXMAIAAAAACAX9LV8Pemfw7NF0iB1/85NzM1Ef+1mUfyehacUVgobQVjACAAAAAAc0bIRNzuyc1Y0hkEmm7xV6Xp/LBlAgMq/ISCHr0Tq44AAzM4AH0AAAAFZAAgAAAAAOYIYoWkX7dGuyKfi3XssUlc7u/gWzqrR9KMkikKVdmSBXMAIAAAAABVF2OYjRTGi9Tw8XCAwZWLpX35Yl271TlNWp6N/nROhAVjACAAAAAAyGLbmHhe8eTQC8L2eDRcezUWULLZ9E8DPic7Mfp8/+4AAzM5AH0AAAAFZAAgAAAAAIy0+bXZi10QC+q7oSOLXK5Fee7VEk/qHSXukfeVIfgzBXMAIAAAAAAQ3IIV/JQCHW95AEbH5zGIHtJqyuPjWPMIZ+VmQHlxEwVjACAAAAAAD3azcNDdohU6tHO6ypT7F0rtydAYIMmLIsX6y7cXVkMAAzQwAH0AAAAFZAAgAAAAAL5SOJQ3LOhgdXJ5v086NNeAl1qonQnchObdpZJ1kHeEBXMAIAAAAAA+tEqTXODtik+ydJZSnUqXF9f18bPeze9eWtR7ExZJgQVjACAAAAAAUd8v2RN1WagYan1LbV+G81vcJKQ6HsX2GSBtnzMH7XEAAzQxAH0AAAAFZAAgAAAAAKl8zcHJRDjSjJeV/WvMxulW1zrTFtaeBy/aKKhadc6UBXMAIAAAAADBdWQl5SBIvtZZLIHszePwkO14W1mQ0izUk2Ov21cPNAVjACAAAAAAHvQLJ2X4ncjVv1BsOd/jbVouRPwf4222WlGSzPyAfnsAAzQyAH0AAAAFZAAgAAAAAFvotcNaoKnVt5CBCOPwjexFO0WGWuaIGL6H/6KSau+6BXMAIAAAAAD2y2mBN5xPu5PJoY2zcr0GnQDtHRBogA5+xzIxccE9fwVjACAAAAAA1OntPAxq1NJ4sfca+ysHcg68mj7QHwdEZQVxHMlV6x0AAzQzAH0AAAAFZAAgAAAAAPezU0/vNT4Q4YKbTbaeHqcwNLT+IjW/Y9QFpIooihjPBXMAIAAAAACj2x4O4rHter8ZnTws5LAP9jJ/6kk9C/V3vL50LoFZHAVjACAAAAAAlZd3bPMUXRhTwLWflrQuKIwtauTswenUiaDi2ibHYYYAAzQ0AH0AAAAFZAAgAAAAAMqpayM2XotEFmm0gwQd9rIzApy0X+7HfOhNk6VU7F5lBXMAIAAAAACJR9+q5T9qFHXFNgGbZnPubG8rkO6cwWhzITQTmd6VgwVjACAAAAAAEEOCUo+ihRGl1kuHlabWBWUFyJPAXSXzpQB4od57cMEAAzQ1AH0AAAAFZAAgAAAAANCeyW+3oebaQk+aqxNVhAcT/BZ5nhsTVdKS3tMrLSvWBXMAIAAAAADxRFMDhkyuEc++WnndMfoUMLNL7T7rWoeblcrpSI6soQVjACAAAAAA1KYQISxmBcGmgDMAjBpTcfQr/oci60Kf4QtEYEXPKSQAAzQ2AH0AAAAFZAAgAAAAAIbo5YBTxXM7HQhl7UP9NNgpPGFkBx871r1B65G47+K8BXMAIAAAAAC21dJSxnEhnxO5gzN5/34BL4von45e1meW92qowzb8fQVjACAAAAAAisxsskU/9ykphpSjB6bMMY+6Tbt6wpjhE2dg1IULAgYAAzQ3AH0AAAAFZAAgAAAAABm/6pF96j26Jm7z5KkY1y33zcAEXLx2n0DwC03bs/ixBXMAIAAAAAD01OMvTZI/mqMgxIhA5nLs068mW+GKl3OW3ilf2D8+LgVjACAAAAAAnPa8PTfcaSSAdzNAC54IMTicbShbtt/cSnFHz7u7g8wAAzQ4AH0AAAAFZAAgAAAAAJ/D3+17gaQdkBqkL2wMwccdmCaVOtxzIkM8VyI4xI5zBXMAIAAAAAAggLVmkc5u+YzBR+oNE+XgLVp64fC6MzUb/Ilu/Jsw0AVjACAAAAAAp5qCK8p0eTvAAUQ8fIOGyb2YM1YflQ8H6ggiWZ9vNI4AAzQ5AH0AAAAFZAAgAAAAAJMRyUW50oaTzspS6A3TUoXyC3gNYQoShUGPakMmeVZrBXMAIAAAAACona2Pqwt4U2PmFrtmu37jB9kQ/12okyAVtYa8TQkDiQVjACAAAAAAx/LOuDwvpaPFJeKLowZW/4q7SUsLtdldB27zc4//alEAAzUwAH0AAAAFZAAgAAAAAByuYl8dBvfaZ0LO/81JW4hYypeNmvLMaxsIdvqMPrWoBXMAIAAAAABNddwobOUJzm9HOUD8BMZJqkNCUCqstHZkC76FIdNg9AVjACAAAAAA4SEPY+qEZ2dCu/9485IEVybiM3Z7szXYM+izxklNm14AAzUxAH0AAAAFZAAgAAAAAHEzLtfmF/sBcYPPdj8867VmmQyU1xK9I/3Y0478azvABXMAIAAAAAAcmyFajZPnBTbO+oLInNwlApBocUekKkxz2hYFeSlQ+gVjACAAAAAA15ibZoBP1/pP27BDIfizDYNRDIpOmj8Ie34FvrtqjhMAAzUyAH0AAAAFZAAgAAAAAJam7JYsZe2cN20ZYm2W3v1pisNt5PLiniMzymBLWyMtBXMAIAAAAABxCsKVMZMTn3n+R2L7pVz5nW804r8HcK0mCBw3jUXKXAVjACAAAAAAElCgoMRrtlONqnyosjIpiz4mQTLq3+b/JUCVEq4QFiAAAzUzAH0AAAAFZAAgAAAAAMXrXx0saZ+5gORmwM2FLuZG6iuO2YS+1IGPoAtDKoKBBXMAIAAAAADIQsxCr8CfFKaBcx8kIeSywnGh7JHjKRJ9vJd9x79y7wVjACAAAAAAPzOTJ088k9QdGUpZ1ubUdkw3pTGkNF8bui4a9wqeo08AAzU0AH0AAAAFZAAgAAAAACbzcUD3INSnCRspOKF7ubne74OK9L0FTZvi9Ay0JVDYBXMAIAAAAADPebVQH8Btk9rhBIoUOdSAdpPvz7qIY4UC2i6IGisSAQVjACAAAAAAe4zSAgMQPjtz2t1DgxW1XOlV+fnNMXt6iQ7iV7DgQz4AAzU1AH0AAAAFZAAgAAAAACUc2CtD1MK/UTxtv+8iA9FoHEyTwdl43HKeSwDw2Lp5BXMAIAAAAACCIduIdw65bQMzRYRfjBJj62bc69T4QqH4QoWanwlvowVjACAAAAAA+i6aTnkoixxSOxDgQM/aWTylOy1m0ViCDU5asOM5ieYAAzU2AH0AAAAFZAAgAAAAAHSaHWs/dnmI9sc7nB50VB2Bzs0kHapMHCQdyVEYY30TBXMAIAAAAACkV22lhEjWv/9/DubfHBAcwJggKI5mIbSK5L2nyqloqQVjACAAAAAA1I5pLbnlFf/EfJlhE0RFIioDjzKrWNh4TO8H/ksrbMcAAzU3AH0AAAAFZAAgAAAAAAL8jhNBG0KXXZhmZ0bPXtfgapJCB/AI+BEHB0eZ3C75BXMAIAAAAADHx/fPa639EBmGV5quLi8IQT600ifiKSOhTDOK19DnzwVjACAAAAAANfWpWWy9iu7pgMEy2aVCggGEtJtXKQG1+3zCf8D6iEkAAzU4AH0AAAAFZAAgAAAAAAxgeclNl09H7HvzD1oLwb2YpFca5eaX90uStYXHilqKBXMAIAAAAACMU5pSxzIzWlQxHyW170Xs9EhD1hURASQk+qkx7K5Y6AVjACAAAAAA/kYlJPSFn2g1l7cy6djV/7wgnlPWphZ0IKSY8uenUF0AAzU5AH0AAAAFZAAgAAAAABmO7QD9vxWMmFjIHz13lyOeV6vHT6mYCsWxF7hb/yOjBXMAIAAAAACT9lmgkiqzuWG24afuzYiCeK9gmJqacmxAruIukd0xEAVjACAAAAAAyiZxtuOZQNSit4wFMJS3jnqLbDzyJ0OtDTKs6r0EO0cAAzYwAH0AAAAFZAAgAAAAAB89SjLtDJkqEghRGyj6aQ/2qvWLNuMROoXmzbYbCMKMBXMAIAAAAAC8sywgND+CjhVTF6HnRQeay8y9/HnVzDI42dEPah28LQVjACAAAAAAzBj8q9Ig4uhIc6rhNDVX1lII9lzfhJ0+ig8viBhdrtQAAzYxAH0AAAAFZAAgAAAAABN2alGq9Aats1mwERNGwL/fIwZSvVCe9/8XMHTFlpUpBXMAIAAAAACuDPjJgvvbBYhbLpjMiWUCsVppiYrhvR+yMysNPN8cZAVjACAAAAAAqcsLIvb3Pe/QKYB9wQ86Ye2OFSAJEIY4ve7LMM3SwGMAAzYyAH0AAAAFZAAgAAAAAL8YB6VAqGBiWD4CBv16IBscg5J7VQCTZu87n6pj+86KBXMAIAAAAAAmxm8e68geeyAdUjSMWBHzUjneVB0pG9TBXIoE6467hAVjACAAAAAA9Kd65vKIUckNPvxl/HHNPJVnFHXyErp4qibmD7BloukAAzYzAH0AAAAFZAAgAAAAAL4yLkCTV5Dmxa5toBu4JT8ge/cITAaURIOuFuOtFUkeBXMAIAAAAAAXoFNQOMGkAj7qEJP0wQafmFSXgWGeorDVbwyOxWLIsgVjACAAAAAAaFrBx0xXIryTe7V/kX+jfPHd0057x7k7MxzDAzi0RpcAAzY0AH0AAAAFZAAgAAAAAEU8DoUp46YtYjNFS9kNXwdYxQ9IW27vCTb+VcqqfnKNBXMAIAAAAADe7vBOgYReE8X78k5ARuUnv4GmzPZzg6SbConf4L2G3wVjACAAAAAAOl/tartywd/fJj5DNRsVH/ml9tJ8KkkCbKObsFe8lHcAAzY1AH0AAAAFZAAgAAAAAPa4yKTtkUtySuWo1ZQsp2QXtPb5SYqzA5vYDnS1P6c0BXMAIAAAAADKnF58R1sXlHlsHIvCBR3YWW/qk54z9CTDhZydkD1cOQVjACAAAAAAfn/jP8K3QUILngCNkydHARyBvBHIFdaJjzV0EXsFruMAAzY2AH0AAAAFZAAgAAAAAN5WJnMBmfgpuQPyonmY5X6OdRvuHw4nhsnGRnFAQ95VBXMAIAAAAACwftzu7KVV1rmGKwXtJjs3cJ1gE3apr8+N0SAg1F2cHwVjACAAAAAAf0XyQQLd/HIYaf9EeAV0o2h12K1AV5piLCpZihznBXoAAzY3AH0AAAAFZAAgAAAAACHvDsaPhoSb6DeGnKQ1QOpGYAgK82qpnqwcmzSeWaJHBXMAIAAAAABRq3C5+dOfnkAHM5Mg5hPB3O4jhwQlBgQWLA7Ph5bhgwVjACAAAAAAm2Ukk5kkQp+PDpBCCefQOqFKKZie4hINim3yvtypsEAAAzY4AH0AAAAFZAAgAAAAAOBePJvccPMJmy515KB1AkXF5Pi8NOG4V8psWy0SPRP+BXMAIAAAAAB3dOJG9xIDtEKCRzeNnPS3bFZepMj8UKBobKpSoCPqpgVjACAAAAAAnu33SngYPOtRgdJ3aBBuxWn80ti3OO6nZJcI6eh0VfQAAzY5AH0AAAAFZAAgAAAAABUvRrDQKEXLMdhnzXRdhiL6AGNs2TojPky+YVLXs+JnBXMAIAAAAAD1kYicbEEcPzD4QtuSYQQWDPq8fuUWGddpWayKn3dT9QVjACAAAAAAUc5dxcbNYY3qMO8+Xm2xis+pH9NjPLrHqHenwDEImAEAAzcwAH0AAAAFZAAgAAAAAOvSnpujeKNen4pqc2HR63C5s5oJ1Vf4CsbKoYQvkwl5BXMAIAAAAACw2+vAMdibzd2YVVNfk81yXkFZP0WLJ82JBxJmXnYE+QVjACAAAAAAnmej008JFQAgdImjk26PYvqdATjRYRufLi+vEVVwtucAAzcxAH0AAAAFZAAgAAAAAAo0xfGG7tJ3GWhgPVhW5Zn239nTD3PadShCNRc9TwdNBXMAIAAAAADZh243oOhenu0s/P/5KZLBDh9ADqKHtSWcXpO9D2sIjgVjACAAAAAAhpNHI4+aRdWHCvZfEjlgpRBz36g05wN9p/hj3NEwc7EAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2FIZh/9N+NeJEQwxYIX5ikQT85xJzulBNReXk8PnG/s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I93Md7QNPGmEEGYU1+VVCqBPBEvXdqHPtTJtMOn06Yk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "GecBFQ1PemlECWZWCl7f74vmsL6eB6mzQ9n6tK6FYfs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QpjhZl+O1ORifgtCZuWAdcP6OKL7IZ2cA46v8FJcV28=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FWXI/yZ1M+2fIboeMCDMlp+I2NwPQDtoM/wWselOPYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uk26nvN/LdRLaBphiBgIZzT0sSpoO1z0RdDWRm/xrSA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hiiYSH1KZovAULc7rlmEU74wCjzDR+mm6ZnsgvFQjMw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hRzvMvWPX0sJme+wck67lwbKDFaWOa+Eyef+JSdc1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PSx5D+zqC9c295dguX4+EobT4IEzfffdfjzC8DWpB5Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QzfXQCVTjPQv2h21v95HYPq8uCsVJ2tPnjv79gAaM9M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XcGDO/dlTcEMLqwcm55UmOqK+KpBmbzZO1LIzX7GPaQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Lf+o4E7YB5ynzUPC6KTyW0lj6Cg9oLIu1Sdd1ODHctA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wAuVn02LAVo5Y+TUocvkoenFYWzpu38k0NmGZOsAjS4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yJGDtveLbbo/0HtCtiTSsvVI/0agg/U1bFaQ0yhK12o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KsEy0zgYcmkM+O/fWF9z3aJGIk22XCk+Aw96HB6JU68=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "p+AnMI5ZxdJMSIEJmXXya+FeH5yubmOdViwUO89j0Rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/jLix56jzeywBtNuGw55lCXyebQoSIhbful0hOKxKDY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fvDvSPomtJsl1S3+8/tzFCE8scHIdJY5hB9CdTEsoFo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "oV5hOJzPXxfTuRdKIlF4uYEoMDuqH+G7/3qgndDr0PM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3ALwcvLj3VOfgD6OqXAO13h1ZkOv46R6+Oy6SUKh53I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gxaB9FJj0IM+InhvAjwWaex3UIZ9SAnDiUd5WHSY/l0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "66NPvDygJzKJqddfNuDuNOpvGajjFRtvhkwfUkiYmXw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1dWcQIocRAcO9XnXYqbhl83jc0RgjQpsrWd8dC27trg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "npos0Uf1DT3ztSCjPVY9EImlRnTHB1KLrvmVSqBQ/8E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "TEI9qBx/tK1l1H0v1scMG8Srmtwo5VxWHADPBSlWrXk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3wUN2ypQKoj+5ASkeIK9ycxhahVxyTmGopigoUAlyYs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o/oksSnUS+nIq6ozWTbB5bJh+NoaPj8deAA23uxiWCk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KExYPruhA31e8xuSwvfUfDcyY/H2Va6taUd0k4yFgLc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/x+dNfxdd/lkx8Z8VZVfoYl7LPoaZ/iKEzZXBrAtIJc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DE4cmjFLPqZlmRomO0qQiruUBtzoCe8ZdNRcfNH92pU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M6EKNcLPw/iojAChgYUSieaBYWcbsjKtB94SaHOr8vk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+qP49lDPeyhaduTvXJgtJEqHNEYANVu9Bg3Bxz7Td9w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ruMrC2VIS+VKbJwCFb3bfkaLTju9nE+yPONV9s0M0Vo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EbjDlSB5JKnDKff4d8hOmaOwJ7B9Q6NQFisLj+DPC+0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "C/yYOTB94edyqAbiQNu8/H7FoG3yRRjHDkMykz4+Mv0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CBxqrejG+qQQq2YTd6iP/06kiu2CxxzBFaZK3Ofb1CM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2ZOQ/fpho+AbDENWBZaln7wRoepIRdhyT648dr8O5cU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EghIgEPz01+myPgj8oid+PgncvobvC7vjvG3THEEQ0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "92CysZYNF8riwAMhdrIPKxfODw9p07cKQy/Snn8XmVY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VO0LeTBQmsEf7sCHzTnZwUPNTqRZ49R8V5E9XnZ/5N4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "exs8BQMJq7U6ZXYgIizT7XN+X/hOmmn4YEuzev9zgSI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qHpS4k1I+gPniNp4CA8TY8lLN36vBYmgbKMFpbYMEqg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+7lWKCKAWFw6gPZdHE6E8KIfI14/fSvtWUmllb5WLi0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YiH/US0q6679hWblFDDKNqUjCgggoU8sUCssTIF1QbU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YgwkKElEubNfvXL9hJxzqQUQtHiXN/OCGxNL1MUZZlM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hZFST4INZTTuhvJlGJeMwlUAK270UCOTCDeBAnN4a7g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "24I1Zw35AuGnK3CqJhbCwYb0IPuu5sCRrM5iyeITOLc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vgD12JB4Q1S/kGPSQ1KOgp386KnG1GbM/5+60oRGcGw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+wNE+OL+CB9d4AUJdVxd56jUJCAXmmk9fapuB2TAc4g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uhQh1B2Pe4RkNw/kPEcgaLenuikKoRf1iyfZhpXdodc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "eu8gjAUIp8ybO204AgeOq5v1neI1yljqy5v3I6lo1lM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7QG6oVbASBAjrnCPxzzUNnuFSFNlKhbuBafkF8pr7Is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PUS1xb2oHSDTdYltutoSSxBiJ1NjxH3l2kA4P1CZLEs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XPMh/JDC/O93gJJCwwgJDb8ssWZvRvezNmKmyn3nIfk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jWz+KGwMk/GOvFAK2rOxF3OjxeZAWfmUQ1HGJ7icw4A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o7XbW68pc6flYigf3LW4WAGUWxpeqxaQLkHUhUR9RZ8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nqR+g60+5U0okbqJadSqGgnC+j1JcP8rwMcfzOs2ACI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hz43qVK95tSfbYFtaE/8fE97XMk1RiO8XpWjwZHB80o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "noZUWlZ8M6KXU5rkifyo8/duw5IL7/fXbJvT7bNmW9k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WONVHCuPSanXDRQQ/3tmyJ0Vq+Lu/4hRaMUf0g0kSuw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UEaj6vQRoIghE8Movd8AGXhtwIOXlP4cBsECIUvE5Y8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "D3n2YcO8+PB4C8brDo7kxKjF9Y844rVkdRMLTgsQkrw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "C+YA0G9KjxZVaWwOMuh/dcnHnHAlYnbFrRl0IEpmsY0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rUnmbmQanxrbFPYYrwyQ53x66OSt27yAvF+s48ezKDc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json
new file mode 100644
index 000000000..b09e96632
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json
@@ -0,0 +1,1160 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDouble",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "0.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gte": {
+                  "$numberDouble": "0.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "1.0"
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$lt": {
+                  "$numberDouble": "1.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$lte": {
+                  "$numberDouble": "1.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "0.0"
+                },
+                "$lt": {
+                  "$numberDouble": "2.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$in": [
+                  {
+                    "$numberDouble": "0.0"
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$gte": {
+                      "$numberDouble": "0.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$gt": {
+                      "$numberDouble": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$lt": {
+                      "$numberDouble": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$lte": {
+                      "$numberDouble": "1.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$gt": {
+                      "$numberDouble": "0.0"
+                    },
+                    "$lt": {
+                      "$numberDouble": "2.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$numberDouble": "0.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$numberDouble": "1.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDouble": {
+                    "$in": [
+                      {
+                        "$numberDouble": "0.0"
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberInt": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gte": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json
new file mode 100644
index 000000000..fa09cb87d
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json
@@ -0,0 +1,749 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDouble",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Double. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedDouble": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "Cq8kAAADcGF5bG9hZAB/JAAABGcAQyQAAAMwAH0AAAAFZAAgAAAAAHgYoMGjEE6fAlAhICv0+doHcVX8CmMVxyq7+jlyGrvmBXMAIAAAAAC/5MQZgTHuIr/O5Z3mXPvqrom5JTQ8IeSpQGhO9sB+8gVjACAAAAAAPMgD8Rqnd94atKnMyPjlTwthUQ710MKJVqgtwNXLFWwAAzEAfQAAAAVkACAAAAAA2kiWNvEc4zunJ1jzvuClFC9hjZMYruKCqAaxq+oY8EAFcwAgAAAAACofIS72Cm6s866UCk+evTH3CvKBj/uZd72sAL608rzTBWMAIAAAAAB7NkTFgsBuPIyxW5KtYZD4uxdgRynoAUwA2RDj3qZNdwADMgB9AAAABWQAIAAAAABkfoBGmU3hjYBvQbjNW19kfXneBQsQQPRfUL3UAwI2cAVzACAAAAAAUpK2BUOqX/DGdX5YJniEZMWkofxHqeAbXceEGJxhp8AFYwAgAAAAAENNdd+fMV7VQzshj6RdvsxqDHYkPDxggdUHw3JbmFBeAAMzAH0AAAAFZAAgAAAAAFNprhQ3ZwIcYbuzLolAT5n/vc14P9kUUQComDu6eFyKBXMAIAAAAAAcx9z9pk32YbPV/sfPZl9ALIEVsqoLXgqWLVK/tP+heAVjACAAAAAA3eqduo9CWE5BePqBq7KCh5++QqXnyjCwybB15Zoeiu4AAzQAfQAAAAVkACAAAAAAODI+pB2pCuB+YmNEUAgtMfNdt3DmSkrJ96gRzLphgb8FcwAgAAAAAAT7dewFDxUDECQ3zVq75/cUN4IP+zsqhkP5+czUwlJIBWMAIAAAAABYcCJA2jocGQiF/vZ9VDEktoK015OqfY64yZhmNPs9GQADNQB9AAAABWQAIAAAAACNAk+yTZ4Ewk1EnotQK8O3h1gg9I7pr9q2+4po1iJVgAVzACAAAAAAUj/LesmtEsgqYVzMJ67umVA11hJTdDXwbxDoQ71vWyUFYwAgAAAAAG32XaKjEO9YTSLMnDR5eiaUpgBQz0n4M3VpBqhWTaEnAAM2AH0AAAAFZAAgAAAAAD/FIrGYFDjyYmVb7oTMVwweWP7A6F9LnyIuNO4MjBnXBXMAIAAAAACIZgJCQRZu7NhuNMyOqCn1tf+DfU1qm10TPCfj5JYV3wVjACAAAAAAZCaO06/DjOBjNrTxB8jdxM7X4XvNu9QTa2Y00kZJwgEAAzcAfQAAAAVkACAAAAAAciRW40ORJLVwchOEpz87Svb+5toAFM6LxDWv928ECwQFcwAgAAAAAN0dipyESIkszfjRzdDi8kAGaa2Hf4wrPAtiWwboZLuxBWMAIAAAAADhvKHhF7zfNRnG8QfiIlKycV6L6iGxbGNKkHligA9rAgADOAB9AAAABWQAIAAAAACZqAyCzYQupJ95mrBJX54yIz9VY7I0WrxpNYElCI4dTQVzACAAAAAA/eyJb6d1xfE+jJlVXMTD3HS/NEYENPVKAuj56Dr2dSEFYwAgAAAAAMfcJKj77c6y/RBQ5hb5LSNdvbYvCAHR59KLnbmxj1gAAAM5AH0AAAAFZAAgAAAAAI5bm3YO0Xgf0VT+qjVTTfvckecM3Cwqj7DTKZXf8/NXBXMAIAAAAAD/m+h8fBhWaHm6Ykuz0WX1xL4Eme3ErLObyEVJf8NCywVjACAAAAAAiGdTXD22l1zDxHeF4NXUTiBnNTsdpzJRwM6riTPuOogAAzEwAH0AAAAFZAAgAAAAANqo4+p6qdtCzcB4BX1wQ6llU7eFBnuu4MtZwp4B6mDlBXMAIAAAAAAGiz+VaukMZ+6IH4jtn4KWWdKK4/W+O+gRioQDrfzpMgVjACAAAAAAl/wlBjSJW/hKkll8HSBCGw4Ce1pJ5rZuhVE09hKq4jQAAzExAH0AAAAFZAAgAAAAAPrFXmHP2Y4YAm7b/aqsdn/DPoDkv7B8egWkfe23XsM1BXMAIAAAAAAGhwpKAr7skeqHm3oseSbO7qKNhmYsuUrECBxJ5k+D2AVjACAAAAAAKSsxERy2OBhb5MiH9/H2BET2oeU6yVihiAoWi/16FroAAzEyAH0AAAAFZAAgAAAAABzjYxwAjXxXc0Uxv18rH8I3my0Aguow0kTwKyxbrm+cBXMAIAAAAADVbqJVr6IdokuhXkEtXF0C2gINLiAjMVN20lE20Vmp2QVjACAAAAAACJ+VAwl9X88mjC76yzkWeL4K6AamNYjbNkpS9B6fQE4AAzEzAH0AAAAFZAAgAAAAAFMm2feF2fFCm/UC6AfIyepX/xJDSmnnolQIBnHcPmb5BXMAIAAAAABLI11kFrQoaNVZFmq/38aRNImPOjdJh0Lo6irI8M/AaAVjACAAAAAAZFgYh4nV8YN+/AAqe/QhKDkNBPg8KraCG7y3bOzhPV4AAzE0AH0AAAAFZAAgAAAAAJvXB3KyNiNtQko4SSzo/9b2qmM2zU9CQTTDfLSBWMgRBXMAIAAAAAAvjuVP7KsLRDeqVqRziTKpBrjVyqKiIbO9Gw8Wl2wFTAVjACAAAAAARuBn3JdQ8so7Gy0XVH0CtlvtRoJWhSrJP6eRIqbyWh8AAzE1AH0AAAAFZAAgAAAAAPGdcxDiid8z8XYnfdDivNMYVPgBKdGOUw6UStU+48CdBXMAIAAAAAARj6g1Ap0eEfuCZ4X2TsEw+Djrhto3fA5nLwPaY0vCTgVjACAAAAAATxLY6SkcLPaoOBJpQsggEqoxgJgiY9seP3fBQM05PckAAzE2AH0AAAAFZAAgAAAAAP5rGPrYGt3aKob5f/ldP0qrW7bmWvqnKY4QwdDWz400BXMAIAAAAADTQkW2ymaaf/bhteOOGmSrIR97bAnJx+yN3yMj1bTeewVjACAAAAAA6O+wIMt3xMITuCxVrqOCNBPX5F122G+/Is+EYkzUvVYAAzE3AH0AAAAFZAAgAAAAAAlz6wJze5UkIxKpJOZFGCOf3v2KByWyI6NB6JM9wNcBBXMAIAAAAABUC7P/neUIHHoZtq0jFVBHY75tSFYr1Y5S16YN5XxC1QVjACAAAAAANv97jMd9JmZ7lMeCzK7jaZHZYsZJNl6N9g9WXzd2om0AAzE4AH0AAAAFZAAgAAAAAFJ8AtHcjia/9Y5pLEc3qVgH5xKiXw12G9Kn2A1EY8McBXMAIAAAAAAxe7Bdw7eUSBk/oAawa7uicTEDgXLymRNhBy1LAxhDvwVjACAAAAAAtOUZ2NeUWwESpq95O92dhqYBt8RtFnjT43E7k9mQF3oAAzE5AH0AAAAFZAAgAAAAAO8uwQUaKFb6vqR3Sv3Wn4QAonC2exOC9lGG1juqP5DtBXMAIAAAAABZf1KyJgQg8/Rf5c02DgDK2aQu0rNCOvaL60ohDHyY+gVjACAAAAAA5nAWj1Ek8p0MLYZEB3yoVFDfBYZ+/ZpIo71u+W9hprcAAzIwAH0AAAAFZAAgAAAAAE8YtqyRsGCeiR6hhiyisR/hccmK4nZqIMzO4lUBmEFzBXMAIAAAAAC1UYOSKqAeG1UJiKjWFVskRhuFKpj9Ezy+lICZvFlN5AVjACAAAAAA37oP30mTzVftI2FL9Uwyls/jqLqbmRDQk7p7nlx44uYAAzIxAH0AAAAFZAAgAAAAAPhCrMausDx1QUIEqp9rUdRKyM6a9AAx7jQ3ILIu8wNIBXMAIAAAAACmH8lotGCiF2q9VQxhsS+7LAZv79VUAsOUALaGxE/EpAVjACAAAAAAhVIkl8p19VZ0gpg32s++Jda3qsVSVB5tV4CKrtjhE3IAAzIyAH0AAAAFZAAgAAAAAOBi/GAYFcstMSJPgp3VkMiuuUUCrZytvqYaU8dwm8v2BXMAIAAAAACEZSZVyD3pKzGlbdwlYmWQhHHTV5SnNLknl2Gw8IaUTQVjACAAAAAAriBex2kK//RPhyVpCYJDBng4l5w8jD3m8BF7dVAP0p8AAzIzAH0AAAAFZAAgAAAAAIQuup+YGfH3mflzWopN8J1X8o8a0d9CSGIvrA5HOzraBXMAIAAAAADYvNLURXsC2ITMqK14LABQBI+hZZ5wNf24JMcKLW+84AVjACAAAAAAGeUzdG2kQrx5XypXJezZmPVzMYuqYZw7Bhbl4EPT0SMAAzI0AH0AAAAFZAAgAAAAAKsh0ADyOnVocFrOrf6MpTrNvAj8iaiE923DPryu124gBXMAIAAAAADg24a8NVE1GyScc6tmnTbmu5ulzO+896fE92lN08MeswVjACAAAAAAbO+DEBY3STVMQN7CbxmHDUBYrDR+80e797u/VmiK4vcAAzI1AH0AAAAFZAAgAAAAAKkVC2Y6HtRmv72tDnPUSjJBvse7SxLqnr09/Uuj9sVVBXMAIAAAAABYNFUkH7ylPMN+Bc3HWX1e0flGYNbtJNCY9SltJCW/UAVjACAAAAAAHlE3RLKcXpXto7Mr8nRgzEsmhjfGh4vcgPxashCSMg4AAzI2AH0AAAAFZAAgAAAAADDggcwcb/Yn1Kk39sOHsv7BO/MfP3m/AJzjGH506Wf9BXMAIAAAAAAYZIsdjICS0+BDyRUPnrSAZfPrwtuMaEDEn0/ijLNQmAVjACAAAAAA1c/sy3255NofBQrnBNSmVkSzMgsGPaaOUJShddVrnuQAAzI3AH0AAAAFZAAgAAAAAEWY7dEUOJBgjOoWVht1wLehsWAzB3rSOBtLgTuM2HC8BXMAIAAAAAAAoswiHRROurjwUW8u8D5EUT+67yvrgpB/j6PzBDAfVwVjACAAAAAALBvQumG8m7/bzJjGWN2cHSAncdN8jMtOSmEhEhGom24AAzI4AH0AAAAFZAAgAAAAAPZaapeAUUFPA7JTCMOWHJa9lnPFh0/gXfAPjA1ezm4ZBXMAIAAAAACmJvLY2nivw7/b3DOKH/X7bBXjJwoowqb1GtEFO3OYgAVjACAAAAAAGCDHuUJusGHKQ+r9nrFChmUUsRcqZKPGsRiLSk5gbFcAAzI5AH0AAAAFZAAgAAAAAK00u6jadxCZAiA+fTsPVDsnW5p5LCr4+kZZZOTDuZlfBXMAIAAAAAAote4zTEYMDgaaQbAdN8Dzv93ljPLdGjJzvnRn3KXgtQVjACAAAAAApZ6l+OrocOqgFek7WOqOP9JruTWZ+iW+5zdL3DZwzhkAAzMwAH0AAAAFZAAgAAAAAFbgabdyymiEVYYwtJSWa7lfl/oYuj/SukzJeDOR6wPVBXMAIAAAAADAFGFjS1vPbN6mQEhkDYTD6V2V23Ys9gUEUMGNvMPkaAVjACAAAAAAeICKly5Xtwmfd4JFD+5e1UWpu4V3KoRim7jeBICDs+UAAzMxAH0AAAAFZAAgAAAAABNMR6UBv2E627CqLtQ/eDYx7OEwQ7JrR4mSHFa1N8tLBXMAIAAAAAAxH4gucI4UmNVB7625C6hFSVCuIpJO3lusJlPuL8H5EQVjACAAAAAA0/uh1hrAlGGna/njCVaCqBwubxkifzF0zjCDQrIJOtUAAzMyAH0AAAAFZAAgAAAAAG8cd6WBneNunlqrQ2EmNf35W7OGObGq9WL4ePX+LUDmBXMAIAAAAAAjJ2+sX87NSis9hBsgb1QprVRnO7Bf+GObCGoUqyPE4wVjACAAAAAAAoJ4Ufdq45T9Aun5FupHlaBCIUsmUn6dXgV9KorpFikAAzMzAH0AAAAFZAAgAAAAAFWOUGkUpy8yf6gB3dio/aOfRKh7XuhvsUj48iESFJrGBXMAIAAAAAAY7sCDMcrUXvNuL6dO0m11WyijzXZvPIcOKob6IpC4PQVjACAAAAAAO/QFjczoznH95Iu0YEVMsU1GA1yxSGL8bcwSweNzAtkAAzM0AH0AAAAFZAAgAAAAAGUrIdKxOihwNmo6B+aG+Ag1qa0+iqdksHOjQj+Oy9bZBXMAIAAAAABwa5dbI2KmzBDNBTQBEkjZv4sPaeRkRNejcjdVymRFKQVjACAAAAAAUtdJucZoQvvPJiy65RonQrxBCcvtfHslpbgLbtWirCYAAzM1AH0AAAAFZAAgAAAAAOx89xV/hRk64/CkM9N2EMK6aldII0c8smdcsZ46NbP8BXMAIAAAAADBF6tfQ+7q9kTuLyuyrSnDgmrdmrXkdhl980i1KHuGHgVjACAAAAAAVc5njbLX1afpsuG662U/OBo4LanEk06lKbQtd95fswgAAzM2AH0AAAAFZAAgAAAAAMkN0L1oQWXhjwn9rAdudcYeN8/5VdCKU8cmDt7BokjsBXMAIAAAAAAT62pGXoRwExe9uvgYOI0hg5tOxilrWfoEmT0SMglWJwVjACAAAAAAhNc5ovIaxgtS856ZBfG+cAcHAz+3ewzB9C6zZoaggj4AAzM3AH0AAAAFZAAgAAAAANxfa4xCoaaB7k1C1RoH1LBhsCbN2yEq15BT9b+iqEC4BXMAIAAAAACAX9LV8Pemfw7NF0iB1/85NzM1Ef+1mUfyehacUVgobQVjACAAAAAAc0bIRNzuyc1Y0hkEmm7xV6Xp/LBlAgMq/ISCHr0Tq44AAzM4AH0AAAAFZAAgAAAAAOYIYoWkX7dGuyKfi3XssUlc7u/gWzqrR9KMkikKVdmSBXMAIAAAAABVF2OYjRTGi9Tw8XCAwZWLpX35Yl271TlNWp6N/nROhAVjACAAAAAAyGLbmHhe8eTQC8L2eDRcezUWULLZ9E8DPic7Mfp8/+4AAzM5AH0AAAAFZAAgAAAAAIy0+bXZi10QC+q7oSOLXK5Fee7VEk/qHSXukfeVIfgzBXMAIAAAAAAQ3IIV/JQCHW95AEbH5zGIHtJqyuPjWPMIZ+VmQHlxEwVjACAAAAAAD3azcNDdohU6tHO6ypT7F0rtydAYIMmLIsX6y7cXVkMAAzQwAH0AAAAFZAAgAAAAAL5SOJQ3LOhgdXJ5v086NNeAl1qonQnchObdpZJ1kHeEBXMAIAAAAAA+tEqTXODtik+ydJZSnUqXF9f18bPeze9eWtR7ExZJgQVjACAAAAAAUd8v2RN1WagYan1LbV+G81vcJKQ6HsX2GSBtnzMH7XEAAzQxAH0AAAAFZAAgAAAAAKl8zcHJRDjSjJeV/WvMxulW1zrTFtaeBy/aKKhadc6UBXMAIAAAAADBdWQl5SBIvtZZLIHszePwkO14W1mQ0izUk2Ov21cPNAVjACAAAAAAHvQLJ2X4ncjVv1BsOd/jbVouRPwf4222WlGSzPyAfnsAAzQyAH0AAAAFZAAgAAAAAFvotcNaoKnVt5CBCOPwjexFO0WGWuaIGL6H/6KSau+6BXMAIAAAAAD2y2mBN5xPu5PJoY2zcr0GnQDtHRBogA5+xzIxccE9fwVjACAAAAAA1OntPAxq1NJ4sfca+ysHcg68mj7QHwdEZQVxHMlV6x0AAzQzAH0AAAAFZAAgAAAAAPezU0/vNT4Q4YKbTbaeHqcwNLT+IjW/Y9QFpIooihjPBXMAIAAAAACj2x4O4rHter8ZnTws5LAP9jJ/6kk9C/V3vL50LoFZHAVjACAAAAAAlZd3bPMUXRhTwLWflrQuKIwtauTswenUiaDi2ibHYYYAAzQ0AH0AAAAFZAAgAAAAAMqpayM2XotEFmm0gwQd9rIzApy0X+7HfOhNk6VU7F5lBXMAIAAAAACJR9+q5T9qFHXFNgGbZnPubG8rkO6cwWhzITQTmd6VgwVjACAAAAAAEEOCUo+ihRGl1kuHlabWBWUFyJPAXSXzpQB4od57cMEAAzQ1AH0AAAAFZAAgAAAAANCeyW+3oebaQk+aqxNVhAcT/BZ5nhsTVdKS3tMrLSvWBXMAIAAAAADxRFMDhkyuEc++WnndMfoUMLNL7T7rWoeblcrpSI6soQVjACAAAAAA1KYQISxmBcGmgDMAjBpTcfQr/oci60Kf4QtEYEXPKSQAAzQ2AH0AAAAFZAAgAAAAAIbo5YBTxXM7HQhl7UP9NNgpPGFkBx871r1B65G47+K8BXMAIAAAAAC21dJSxnEhnxO5gzN5/34BL4von45e1meW92qowzb8fQVjACAAAAAAisxsskU/9ykphpSjB6bMMY+6Tbt6wpjhE2dg1IULAgYAAzQ3AH0AAAAFZAAgAAAAABm/6pF96j26Jm7z5KkY1y33zcAEXLx2n0DwC03bs/ixBXMAIAAAAAD01OMvTZI/mqMgxIhA5nLs068mW+GKl3OW3ilf2D8+LgVjACAAAAAAnPa8PTfcaSSAdzNAC54IMTicbShbtt/cSnFHz7u7g8wAAzQ4AH0AAAAFZAAgAAAAAJ/D3+17gaQdkBqkL2wMwccdmCaVOtxzIkM8VyI4xI5zBXMAIAAAAAAggLVmkc5u+YzBR+oNE+XgLVp64fC6MzUb/Ilu/Jsw0AVjACAAAAAAp5qCK8p0eTvAAUQ8fIOGyb2YM1YflQ8H6ggiWZ9vNI4AAzQ5AH0AAAAFZAAgAAAAAJMRyUW50oaTzspS6A3TUoXyC3gNYQoShUGPakMmeVZrBXMAIAAAAACona2Pqwt4U2PmFrtmu37jB9kQ/12okyAVtYa8TQkDiQVjACAAAAAAx/LOuDwvpaPFJeKLowZW/4q7SUsLtdldB27zc4//alEAAzUwAH0AAAAFZAAgAAAAAByuYl8dBvfaZ0LO/81JW4hYypeNmvLMaxsIdvqMPrWoBXMAIAAAAABNddwobOUJzm9HOUD8BMZJqkNCUCqstHZkC76FIdNg9AVjACAAAAAA4SEPY+qEZ2dCu/9485IEVybiM3Z7szXYM+izxklNm14AAzUxAH0AAAAFZAAgAAAAAHEzLtfmF/sBcYPPdj8867VmmQyU1xK9I/3Y0478azvABXMAIAAAAAAcmyFajZPnBTbO+oLInNwlApBocUekKkxz2hYFeSlQ+gVjACAAAAAA15ibZoBP1/pP27BDIfizDYNRDIpOmj8Ie34FvrtqjhMAAzUyAH0AAAAFZAAgAAAAAJam7JYsZe2cN20ZYm2W3v1pisNt5PLiniMzymBLWyMtBXMAIAAAAABxCsKVMZMTn3n+R2L7pVz5nW804r8HcK0mCBw3jUXKXAVjACAAAAAAElCgoMRrtlONqnyosjIpiz4mQTLq3+b/JUCVEq4QFiAAAzUzAH0AAAAFZAAgAAAAAMXrXx0saZ+5gORmwM2FLuZG6iuO2YS+1IGPoAtDKoKBBXMAIAAAAADIQsxCr8CfFKaBcx8kIeSywnGh7JHjKRJ9vJd9x79y7wVjACAAAAAAPzOTJ088k9QdGUpZ1ubUdkw3pTGkNF8bui4a9wqeo08AAzU0AH0AAAAFZAAgAAAAACbzcUD3INSnCRspOKF7ubne74OK9L0FTZvi9Ay0JVDYBXMAIAAAAADPebVQH8Btk9rhBIoUOdSAdpPvz7qIY4UC2i6IGisSAQVjACAAAAAAe4zSAgMQPjtz2t1DgxW1XOlV+fnNMXt6iQ7iV7DgQz4AAzU1AH0AAAAFZAAgAAAAACUc2CtD1MK/UTxtv+8iA9FoHEyTwdl43HKeSwDw2Lp5BXMAIAAAAACCIduIdw65bQMzRYRfjBJj62bc69T4QqH4QoWanwlvowVjACAAAAAA+i6aTnkoixxSOxDgQM/aWTylOy1m0ViCDU5asOM5ieYAAzU2AH0AAAAFZAAgAAAAAHSaHWs/dnmI9sc7nB50VB2Bzs0kHapMHCQdyVEYY30TBXMAIAAAAACkV22lhEjWv/9/DubfHBAcwJggKI5mIbSK5L2nyqloqQVjACAAAAAA1I5pLbnlFf/EfJlhE0RFIioDjzKrWNh4TO8H/ksrbMcAAzU3AH0AAAAFZAAgAAAAAAL8jhNBG0KXXZhmZ0bPXtfgapJCB/AI+BEHB0eZ3C75BXMAIAAAAADHx/fPa639EBmGV5quLi8IQT600ifiKSOhTDOK19DnzwVjACAAAAAANfWpWWy9iu7pgMEy2aVCggGEtJtXKQG1+3zCf8D6iEkAAzU4AH0AAAAFZAAgAAAAAAxgeclNl09H7HvzD1oLwb2YpFca5eaX90uStYXHilqKBXMAIAAAAACMU5pSxzIzWlQxHyW170Xs9EhD1hURASQk+qkx7K5Y6AVjACAAAAAA/kYlJPSFn2g1l7cy6djV/7wgnlPWphZ0IKSY8uenUF0AAzU5AH0AAAAFZAAgAAAAABmO7QD9vxWMmFjIHz13lyOeV6vHT6mYCsWxF7hb/yOjBXMAIAAAAACT9lmgkiqzuWG24afuzYiCeK9gmJqacmxAruIukd0xEAVjACAAAAAAyiZxtuOZQNSit4wFMJS3jnqLbDzyJ0OtDTKs6r0EO0cAAzYwAH0AAAAFZAAgAAAAAB89SjLtDJkqEghRGyj6aQ/2qvWLNuMROoXmzbYbCMKMBXMAIAAAAAC8sywgND+CjhVTF6HnRQeay8y9/HnVzDI42dEPah28LQVjACAAAAAAzBj8q9Ig4uhIc6rhNDVX1lII9lzfhJ0+ig8viBhdrtQAAzYxAH0AAAAFZAAgAAAAABN2alGq9Aats1mwERNGwL/fIwZSvVCe9/8XMHTFlpUpBXMAIAAAAACuDPjJgvvbBYhbLpjMiWUCsVppiYrhvR+yMysNPN8cZAVjACAAAAAAqcsLIvb3Pe/QKYB9wQ86Ye2OFSAJEIY4ve7LMM3SwGMAAzYyAH0AAAAFZAAgAAAAAL8YB6VAqGBiWD4CBv16IBscg5J7VQCTZu87n6pj+86KBXMAIAAAAAAmxm8e68geeyAdUjSMWBHzUjneVB0pG9TBXIoE6467hAVjACAAAAAA9Kd65vKIUckNPvxl/HHNPJVnFHXyErp4qibmD7BloukAAzYzAH0AAAAFZAAgAAAAAL4yLkCTV5Dmxa5toBu4JT8ge/cITAaURIOuFuOtFUkeBXMAIAAAAAAXoFNQOMGkAj7qEJP0wQafmFSXgWGeorDVbwyOxWLIsgVjACAAAAAAaFrBx0xXIryTe7V/kX+jfPHd0057x7k7MxzDAzi0RpcAAzY0AH0AAAAFZAAgAAAAAEU8DoUp46YtYjNFS9kNXwdYxQ9IW27vCTb+VcqqfnKNBXMAIAAAAADe7vBOgYReE8X78k5ARuUnv4GmzPZzg6SbConf4L2G3wVjACAAAAAAOl/tartywd/fJj5DNRsVH/ml9tJ8KkkCbKObsFe8lHcAAzY1AH0AAAAFZAAgAAAAAPa4yKTtkUtySuWo1ZQsp2QXtPb5SYqzA5vYDnS1P6c0BXMAIAAAAADKnF58R1sXlHlsHIvCBR3YWW/qk54z9CTDhZydkD1cOQVjACAAAAAAfn/jP8K3QUILngCNkydHARyBvBHIFdaJjzV0EXsFruMAAzY2AH0AAAAFZAAgAAAAAN5WJnMBmfgpuQPyonmY5X6OdRvuHw4nhsnGRnFAQ95VBXMAIAAAAACwftzu7KVV1rmGKwXtJjs3cJ1gE3apr8+N0SAg1F2cHwVjACAAAAAAf0XyQQLd/HIYaf9EeAV0o2h12K1AV5piLCpZihznBXoAAzY3AH0AAAAFZAAgAAAAACHvDsaPhoSb6DeGnKQ1QOpGYAgK82qpnqwcmzSeWaJHBXMAIAAAAABRq3C5+dOfnkAHM5Mg5hPB3O4jhwQlBgQWLA7Ph5bhgwVjACAAAAAAm2Ukk5kkQp+PDpBCCefQOqFKKZie4hINim3yvtypsEAAAzY4AH0AAAAFZAAgAAAAAOBePJvccPMJmy515KB1AkXF5Pi8NOG4V8psWy0SPRP+BXMAIAAAAAB3dOJG9xIDtEKCRzeNnPS3bFZepMj8UKBobKpSoCPqpgVjACAAAAAAnu33SngYPOtRgdJ3aBBuxWn80ti3OO6nZJcI6eh0VfQAAzY5AH0AAAAFZAAgAAAAABUvRrDQKEXLMdhnzXRdhiL6AGNs2TojPky+YVLXs+JnBXMAIAAAAAD1kYicbEEcPzD4QtuSYQQWDPq8fuUWGddpWayKn3dT9QVjACAAAAAAUc5dxcbNYY3qMO8+Xm2xis+pH9NjPLrHqHenwDEImAEAAzcwAH0AAAAFZAAgAAAAAOvSnpujeKNen4pqc2HR63C5s5oJ1Vf4CsbKoYQvkwl5BXMAIAAAAACw2+vAMdibzd2YVVNfk81yXkFZP0WLJ82JBxJmXnYE+QVjACAAAAAAnmej008JFQAgdImjk26PYvqdATjRYRufLi+vEVVwtucAAzcxAH0AAAAFZAAgAAAAAAo0xfGG7tJ3GWhgPVhW5Zn239nTD3PadShCNRc9TwdNBXMAIAAAAADZh243oOhenu0s/P/5KZLBDh9ADqKHtSWcXpO9D2sIjgVjACAAAAAAhpNHI4+aRdWHCvZfEjlgpRBz36g05wN9p/hj3NEwc7EAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDouble": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json
new file mode 100644
index 000000000..59a304166
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json
@@ -0,0 +1,1160 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDouble",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Double. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDouble": {
+                  "$numberDouble": "2"
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedDouble": {
+              "$numberDouble": "1"
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedDouble": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDouble": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "HI88j1zrIsFoijIXKybr9mYubNV5uVeODyLHFH4Ueco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wXVD/HSbBljko0jJcaxJ1nrzs2+pchLQqYR3vywS8SU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KhscCh+tt/pp8lxtKZQSPPUU94RvJYPKG/sjtzIa4Ws=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RISnuNrTTVNW5HnwCgQJ301pFw8DOcYrAMQIwVwjOkI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Ra5zukLh2boua0Bh74qA+mtIoixGXlsNsxiJqHtqdTI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "eqr0v+NNWXWszi9ni8qH58Q6gw5x737tJvH3lPaNHO4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d42QupriWIwGrFAquXNFi0ehEuidIbHLFZtg1Sm2nN8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2azRVxaaTIJKcgY2FU012gcyP8Y05cRDpfUaMnCBaQU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3nlgkM4K/AAcHesRYYdEu24UGetHodVnVfHzw4yxZBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hqy91FNmAAac2zUaPO6eWFkx0/37rOWGrwXN+fzL0tU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "akX+fmscSDSF9pB5MPj56iaJPtohr0hfXNk/OPWsGv8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1ZvUb10Q7cN4cNLktd5yNjqgtawsYnkbeVBZV6WuY/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "otCwtuKiY4hCyXvYzXvo10OcnzZppebo38KsAlq49QM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Mty8EscckeT/dhMfrPFyDbLnmMOcYRUQ3mLK4KTu6V8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tnvgLLkJINO7csREYu4dEVe1ICrBeu7OP+HdfoX3M2E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kOefsHgEVhkJ17UuP7Dxogy6sAQbzf1SFPKCj6XRlrQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F+JQ79xavpaHdJzdhvwyHbzdZJLNHAymc/+67La3gao=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NCZ9zp5rDRceENuSgAfTLEyKg0YgmXAhK0B8WSj7+Pw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wL1CJ7cYR5slx8mHq++uMdjDfkt9037lQTUztEMF56M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "txefkzTMITZE+XvvRFZ7QcgwDT/7m8jNmxRk4QBaoZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jFunW3v1tSYMyZtQQD28eEy9qqDp4Kqo7gMN29N4bfQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QMO915KUiS3X3R1bU1YoafVM2s0NeHo3EjgTA9PnGwY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nwdKJEXdilzvb7494vbuDJ+y6SrfJahza1dYIsHIWVI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vpWMX+T/VXXajFo0UbuYjtp0AEzBU0Y+lP+ih2EQ7mg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1lmzG0J1DhKDRhhq5y5Buygu4G8eV2X0t7kUY90EohM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SiKqpXqO0trwhFvBWK274hMklpCgMhNs/JY84yyn/NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7cPGPYCKPTay+ZR9Gx6oOueduOgaFrSuAXmNDpDHXdI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4THEYvAkjs2Fh7FIe5LC45P4i4N0L7ob67UOVbhp6Nk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "B+UGsChLLZR7iqnt8yq91OgmTgwiUKTJhFxY4NT0O6c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X1uYwBCsCg1H+PnKdwtBqXlt0zKEURi8bOM940GcPfk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xYOgT5l7shlNXCwHlguovmDkcEnF8dXyYlTyYrgZ8GE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vFMTZqV8bh1+gcKzTkXweMddJlgdUnwX0DWzUUaMok4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4HI0y9FrtleZxZ7M6INdNhLelrQ2Rv/+ykWCBl+tMC8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jpJ0bBE474OUkn1vUiLWumIBtYmwc7J5+LQU/nyeLQc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jQTPeXZvdxY/DjtPfYfKUArIDsf0E9MVFy2O26sv1ec=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QLLto0ExR2ZYMGqlyaMZc/hXFFTlwmgtKbiVq/xJIeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yBJNviU1nchbGbhx6InXCVRXa90sEepz1EwbYuKXu2U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jpEf0vHxrPu9gTJutNXSi2g/2Mc4WXFEN7yHonZEb7A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "E09kLFckMYwNuhggMxmPtwndyvIAx+Vl+b2CV6FP75s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "N+ue6/cLPb5NssmJCCeo18LlbKPz6r2z20AsnTKRvOo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yVQNZP8hhsvNGyDph2QP2qTNdXZTiIEVineKg+Qf33o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cSC9uI+9c5S8X+0G7amVyug1p0ZlgBsbEDYYyezBevQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1NpZGjoQzuQtekj80Rifxe9HbE08W07dfwxaFHaVn84=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "5Ghuq/8l11Ug9Uf/RTwf9On3OxOwIXUcb9soiy4J7/w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0LWKaEty6ywxLFhDaAqulqfMnYc+tgPfH4apyEeKg80=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OwSthmCBtt6NIAoAh7aCbj82Yr/+9t8U7WuBQhFT3AQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "iYiyg6/1isqbMdvFPIGucu3cNM4NAZNtJhHpGZ4eM+c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "waBgs8jWuGJPIF5zCRh6OmIyfK5GCBQgTMfmKSR2wyY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1Jdtbe2BKJXPU2G9ywOrlODZ/cNYEQlKzAW3aMe1Hy4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xaLEnNUS/2ySerBpb9dN/D31t+wYcKekwTfkwtni0Mc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bIVBrOhOvr6cL55Tr24+B+CC9MiG7U6K54aAr2IXXuw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6Cdq5wroGu2TEFnekuT7LhOpd/K/+PcipIljcHU9QL4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "K5l64vI4S/pLviLW6Pl0U3iQkI3ge0xg4RAHcEsyKJo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bzhuvZ0Ls22yIOX+Hz51eAHlSuDbWR/e0u4EhfdpHbc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Qv+fr6uD4o0bZRp69QJCFL6zvn3G82c7L+N1IFzj7H0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XAmISMbD3aEyQT+BQEphCKFNa0F0GDKFuhM9cGceKoQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4VLCokntMfm1AogpUnYGvhV7nllWSo3mS3hVESMy+hA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xiXNLj/CipEH63Vb5cidi8q9X47EF4f3HtJSOH7mfM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4XlCYfYBjI9XA5zOSgTiEBYcZsdwyXL+f5XtH2xUIOc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "k6DfQy7ZYJIkEly2B5hjOZznL4NcgMkllZjJLb7yq7w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZzM6gwWesa3lxbZVZthpPFs2s3GV0RZREE2zOMhBRBo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "US+jeMeeOd7J0wR0efJtq2/18lcO8YFvhT4O3DeaonQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b6iSxiI1FM9SzxuG1bHqGA1i4+3GOi0/SPW00XB4L7o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kn3LsxAVkzIZKK9I6fi0Cctr0yjXOYgaQWMCoj4hLpM=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json
new file mode 100644
index 000000000..634230eac
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json
@@ -0,0 +1,1129 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDouble",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Double. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedDouble": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2FIZh/9N+NeJEQwxYIX5ikQT85xJzulBNReXk8PnG/s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I93Md7QNPGmEEGYU1+VVCqBPBEvXdqHPtTJtMOn06Yk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "GecBFQ1PemlECWZWCl7f74vmsL6eB6mzQ9n6tK6FYfs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QpjhZl+O1ORifgtCZuWAdcP6OKL7IZ2cA46v8FJcV28=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FWXI/yZ1M+2fIboeMCDMlp+I2NwPQDtoM/wWselOPYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uk26nvN/LdRLaBphiBgIZzT0sSpoO1z0RdDWRm/xrSA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hiiYSH1KZovAULc7rlmEU74wCjzDR+mm6ZnsgvFQjMw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hRzvMvWPX0sJme+wck67lwbKDFaWOa+Eyef+JSdc1s4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PSx5D+zqC9c295dguX4+EobT4IEzfffdfjzC8DWpB5Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QzfXQCVTjPQv2h21v95HYPq8uCsVJ2tPnjv79gAaM9M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XcGDO/dlTcEMLqwcm55UmOqK+KpBmbzZO1LIzX7GPaQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Lf+o4E7YB5ynzUPC6KTyW0lj6Cg9oLIu1Sdd1ODHctA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wAuVn02LAVo5Y+TUocvkoenFYWzpu38k0NmGZOsAjS4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yJGDtveLbbo/0HtCtiTSsvVI/0agg/U1bFaQ0yhK12o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KsEy0zgYcmkM+O/fWF9z3aJGIk22XCk+Aw96HB6JU68=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "p+AnMI5ZxdJMSIEJmXXya+FeH5yubmOdViwUO89j0Rc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/jLix56jzeywBtNuGw55lCXyebQoSIhbful0hOKxKDY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fvDvSPomtJsl1S3+8/tzFCE8scHIdJY5hB9CdTEsoFo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "oV5hOJzPXxfTuRdKIlF4uYEoMDuqH+G7/3qgndDr0PM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3ALwcvLj3VOfgD6OqXAO13h1ZkOv46R6+Oy6SUKh53I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gxaB9FJj0IM+InhvAjwWaex3UIZ9SAnDiUd5WHSY/l0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "66NPvDygJzKJqddfNuDuNOpvGajjFRtvhkwfUkiYmXw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1dWcQIocRAcO9XnXYqbhl83jc0RgjQpsrWd8dC27trg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "npos0Uf1DT3ztSCjPVY9EImlRnTHB1KLrvmVSqBQ/8E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "TEI9qBx/tK1l1H0v1scMG8Srmtwo5VxWHADPBSlWrXk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3wUN2ypQKoj+5ASkeIK9ycxhahVxyTmGopigoUAlyYs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o/oksSnUS+nIq6ozWTbB5bJh+NoaPj8deAA23uxiWCk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KExYPruhA31e8xuSwvfUfDcyY/H2Va6taUd0k4yFgLc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "/x+dNfxdd/lkx8Z8VZVfoYl7LPoaZ/iKEzZXBrAtIJc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DE4cmjFLPqZlmRomO0qQiruUBtzoCe8ZdNRcfNH92pU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M6EKNcLPw/iojAChgYUSieaBYWcbsjKtB94SaHOr8vk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+qP49lDPeyhaduTvXJgtJEqHNEYANVu9Bg3Bxz7Td9w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ruMrC2VIS+VKbJwCFb3bfkaLTju9nE+yPONV9s0M0Vo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EbjDlSB5JKnDKff4d8hOmaOwJ7B9Q6NQFisLj+DPC+0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "C/yYOTB94edyqAbiQNu8/H7FoG3yRRjHDkMykz4+Mv0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CBxqrejG+qQQq2YTd6iP/06kiu2CxxzBFaZK3Ofb1CM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2ZOQ/fpho+AbDENWBZaln7wRoepIRdhyT648dr8O5cU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "EghIgEPz01+myPgj8oid+PgncvobvC7vjvG3THEEQ0M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "92CysZYNF8riwAMhdrIPKxfODw9p07cKQy/Snn8XmVY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VO0LeTBQmsEf7sCHzTnZwUPNTqRZ49R8V5E9XnZ/5N4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "exs8BQMJq7U6ZXYgIizT7XN+X/hOmmn4YEuzev9zgSI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qHpS4k1I+gPniNp4CA8TY8lLN36vBYmgbKMFpbYMEqg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+7lWKCKAWFw6gPZdHE6E8KIfI14/fSvtWUmllb5WLi0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YiH/US0q6679hWblFDDKNqUjCgggoU8sUCssTIF1QbU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YgwkKElEubNfvXL9hJxzqQUQtHiXN/OCGxNL1MUZZlM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hZFST4INZTTuhvJlGJeMwlUAK270UCOTCDeBAnN4a7g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "24I1Zw35AuGnK3CqJhbCwYb0IPuu5sCRrM5iyeITOLc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vgD12JB4Q1S/kGPSQ1KOgp386KnG1GbM/5+60oRGcGw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+wNE+OL+CB9d4AUJdVxd56jUJCAXmmk9fapuB2TAc4g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uhQh1B2Pe4RkNw/kPEcgaLenuikKoRf1iyfZhpXdodc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "eu8gjAUIp8ybO204AgeOq5v1neI1yljqy5v3I6lo1lM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7QG6oVbASBAjrnCPxzzUNnuFSFNlKhbuBafkF8pr7Is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "PUS1xb2oHSDTdYltutoSSxBiJ1NjxH3l2kA4P1CZLEs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XPMh/JDC/O93gJJCwwgJDb8ssWZvRvezNmKmyn3nIfk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jWz+KGwMk/GOvFAK2rOxF3OjxeZAWfmUQ1HGJ7icw4A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o7XbW68pc6flYigf3LW4WAGUWxpeqxaQLkHUhUR9RZ8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nqR+g60+5U0okbqJadSqGgnC+j1JcP8rwMcfzOs2ACI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Hz43qVK95tSfbYFtaE/8fE97XMk1RiO8XpWjwZHB80o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "noZUWlZ8M6KXU5rkifyo8/duw5IL7/fXbJvT7bNmW9k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WONVHCuPSanXDRQQ/3tmyJ0Vq+Lu/4hRaMUf0g0kSuw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UEaj6vQRoIghE8Movd8AGXhtwIOXlP4cBsECIUvE5Y8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "D3n2YcO8+PB4C8brDo7kxKjF9Y844rVkdRMLTgsQkrw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "C+YA0G9KjxZVaWwOMuh/dcnHnHAlYnbFrRl0IEpmsY0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rUnmbmQanxrbFPYYrwyQ53x66OSt27yAvF+s48ezKDc=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json
new file mode 100644
index 000000000..cdc9f28e7
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json
@@ -0,0 +1,1164 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDouble",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Double. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDouble": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDouble": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedDouble": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDouble": {
+                  "$numberDouble": "2"
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDouble": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedDouble": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedDouble": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDouble",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDouble": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6YrBn2ofIw1b5ooakrLOwF41BWrps8OO0H9WH4/rtlE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "n+XAuFnP8Dov9TnhGFxNx0K/MnVM9WbJ7RouEu0ndO0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yRXojuVdn5GQtD97qYlaCL6cOLmZ7Cvcb3wFjkLUIdM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DuIkdRPITRs55I4SZmgomAHCIsDQmXRhW8+MOznkzSk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SsBk+Et1lTbU+QRPx+xyJ/jMkmfG+QCvQEpip2YYrzA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "crCIzOd8KhHvvUlX7M1v9bhvU4pLdTc+X2SuqoKU5Ek=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "YOWdCw4UrqnxkAaVjqmC4sKQDMVMHEpFGnlxpxdaU6E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "M3SShp81Ff8tQ632qKbv9MUcN6wjDaBReI0VXNu6Xh4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gzHlSPxpM0hT75kQvWFzGlOxKvDoiKQZOr19V6l2zXI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "s3JnppOGYw9SL2Q1kMAZs948v2F5PrpXjGei/HioDWs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cG6+3Gk/zEH68P/uuuwiAUVCuyJwa1LeV+t29FlPPAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dupdvR3AyJtM+g9NDKiaLVOtGca387JQp8w+V03m7Ig=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JqEQc5svj2jTvZ6LLA5ivE+kTb/0aRemSEmxk4G7Zrg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "szcXXXKnob+p3SoM4yED2R920LeJ7cVsclPMFTe4CeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "o1QoGVXmuBdHwHm7aCtGMlMVKrjFdYvJXpoq6uhIAZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Jfm5wPlqqLCJRGQIqRq2NGmpn7s0Vrih2H3YAOoI2YU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zMHLb8ARbsYo8Ld05bqnGFf1Usha6EGb8QKwdSAyps0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yQdtq9lh5pugL7/i0Bj/PuZUUBUIzf+7wj1rl5y736w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wGWVZdO7qIuyDg/BqDgqjgoQ02h5YYgwXQB1oCin2NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "by9HMLj6NTEpgztZ5HSN6GxImkXPcaFINYDzgZY33X8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tWo0vbasi7bXmn/MsOx13VC1IsWtpx/nYp0uj4iMzdA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tQQpndUYd5O87lOtrGjH3wl9VsOK0ray7RMasL90sBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cQjXEDCMsOpKLLf+vlTgIHA+cbSJdzqhbSX9Wvh95aA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7yMpU48IxK9SzP2cx3VnTownGEwFmeFofuuFT97SuuY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kSOx1kz0CmBgzKQHZlo65ZUY1DIv9A99JRm+Us2y6Ew=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ubQpdPBe6/xvtr+AcXdfYLSvYCR4ot0tivehkCsupb4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xal+iCJ6FTefRQToyoNksc9NCZShyn04NDGi4IYrcoM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d7jU4iOK50xHxlkSifcxlZFCM46TSgQzoYivxG3HNLY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tJvl2nsBLBVzL3pp6sKWCL4UXeh3q/roYBJjSb74ve0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OIUCaKRvIx9t1w6Hxlz1IcQTdPNCfdRNwnnTm10W+X0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A9tvzsiElotOUVIB4CqfQp9mAwqvTM35YkmAR170aHA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lI8gpK7hpb7c9x4RQugsxMnQay5LZJmwslZdvMx/dcE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dNCzh40U0XvdKnSDi3HRQOWQftEsDVqc4uUvsVFGoq8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "IP+iwEBWBwVVZIdpaMu8k5+soFCz+TZkYn3drKZ9grE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pnqyh6e0y5svHkJDShlN9CHV0WvMBE4QbtJpQw5ZCXc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "elEl42tbVDoRTLjAhZUFEtXiut4b3PVhg/1ZLZSQdtE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vHuu2FxwclMHqyE6JBYbTYgbEkB0dqb/JuaxsvfwsmY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xTf7NCe3Gf8QpE78HR5OknlLTKfs9J+RN9UZpH6fnso=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XiWSasRnJAulGR6+LCVD3mwRObXylqYWR9jvpywq12c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MZMxEQ5ikx0PG1YFIExv0UnTZogsvgeOEZTpzvBDn4w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yZMyMZBDrWbAhvnic7vvIYhmO9m5H2iuv0c8KNZrBzY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xxM14hTPY5j0vvcK2C7YAEjzdsfUTFHozHC0hEo1bxI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+01rqR1xVwkpGXcstbk1ItJqFVjH6Q8MGxEN3Cm9Y1A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xOpLV0Z2VTRJ3iWtnWZcsyjXubTIkYWo31cO+HV1o1k=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BWUOLqgLBqc5NwxVlSV5H3KFQPXbCp7mdo+jF+8cJqY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "fuQb1S6xZDGlrEbK+kI23aL53PP1PVNwqICnZNt9Yzg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfscnoibFttahLdPVC4Ee+47ewGFKpDSU7M6HX19bKE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rpSW2awybNVeKtat91VFxqbINoTfNhPfQAu+d73Xtf8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "9M/CP9ccOIIj2LLFmE0GFDO0Ban2wsNalEXfM6+h+1s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WrEMG49l1ye4MhXs5ZS9tz8P6h+hDvthIg/2wW9ne1Q=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ImNhbfeyfH8qIEeA5ic0s3dAQBdzzTBS+CPsNih9vZ0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dWP33YDSn04UKJN2ogh2Rui0iW/0q2y18OCDRVcfyoo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "lYv0isAtfGh6H9tdp3cp2eHU7q2J+uk7QrgcxtK3w7Y=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "VGMoamB/+7zTOYcY/pqJc96xlv2PdW4hwsIAEIslTDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yNeBWMF7BnD9wVwz2PgJsvWr77QiVvvWUvJF0+fqBug=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SfpvObJ+tJBXSvqeN7vlOfmhYign635lciYAJIjUtY8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dsen4NqjzVGjpjufiTMs3+gqeD09EbnuogPgxrJECwg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "pxCWVM3sn19NsFEpgHbgLa+PmYlhN3mMiP0Wk8kJhYw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q11KNvJszjYIB9n9HcC+N4uz11a3eRj1L3BH9scKMDQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "A1PmkgcEToWh1JiVWE6mI5jUu7poxWWuCUt/cgRUUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "qJo3Hu4PJeanL7XEaWXO/n3YsodhZyd+MJOOmB9Kpd8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "BkBKLO8URFscfRY9Bav/1+L9mLohDgNr/MkZtGiraIs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "rZq5WA3Hx3xthOyHAJXK//f8pE2qbz7YKu3TIMp9GFY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X07a/Lm80p5xd4RFs1dNmw+90tmPDPdGiAKVZkxd4zY=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDouble": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "HI88j1zrIsFoijIXKybr9mYubNV5uVeODyLHFH4Ueco=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wXVD/HSbBljko0jJcaxJ1nrzs2+pchLQqYR3vywS8SU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "KhscCh+tt/pp8lxtKZQSPPUU94RvJYPKG/sjtzIa4Ws=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RISnuNrTTVNW5HnwCgQJ301pFw8DOcYrAMQIwVwjOkI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Ra5zukLh2boua0Bh74qA+mtIoixGXlsNsxiJqHtqdTI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "eqr0v+NNWXWszi9ni8qH58Q6gw5x737tJvH3lPaNHO4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "d42QupriWIwGrFAquXNFi0ehEuidIbHLFZtg1Sm2nN8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "2azRVxaaTIJKcgY2FU012gcyP8Y05cRDpfUaMnCBaQU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "3nlgkM4K/AAcHesRYYdEu24UGetHodVnVfHzw4yxZBM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hqy91FNmAAac2zUaPO6eWFkx0/37rOWGrwXN+fzL0tU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "akX+fmscSDSF9pB5MPj56iaJPtohr0hfXNk/OPWsGv8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1ZvUb10Q7cN4cNLktd5yNjqgtawsYnkbeVBZV6WuY/I=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "otCwtuKiY4hCyXvYzXvo10OcnzZppebo38KsAlq49QM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Mty8EscckeT/dhMfrPFyDbLnmMOcYRUQ3mLK4KTu6V8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "tnvgLLkJINO7csREYu4dEVe1ICrBeu7OP+HdfoX3M2E=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kOefsHgEVhkJ17UuP7Dxogy6sAQbzf1SFPKCj6XRlrQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F+JQ79xavpaHdJzdhvwyHbzdZJLNHAymc/+67La3gao=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "NCZ9zp5rDRceENuSgAfTLEyKg0YgmXAhK0B8WSj7+Pw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wL1CJ7cYR5slx8mHq++uMdjDfkt9037lQTUztEMF56M=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "txefkzTMITZE+XvvRFZ7QcgwDT/7m8jNmxRk4QBaoZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jFunW3v1tSYMyZtQQD28eEy9qqDp4Kqo7gMN29N4bfQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QMO915KUiS3X3R1bU1YoafVM2s0NeHo3EjgTA9PnGwY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "nwdKJEXdilzvb7494vbuDJ+y6SrfJahza1dYIsHIWVI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vpWMX+T/VXXajFo0UbuYjtp0AEzBU0Y+lP+ih2EQ7mg=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1lmzG0J1DhKDRhhq5y5Buygu4G8eV2X0t7kUY90EohM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SiKqpXqO0trwhFvBWK274hMklpCgMhNs/JY84yyn/NE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7cPGPYCKPTay+ZR9Gx6oOueduOgaFrSuAXmNDpDHXdI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4THEYvAkjs2Fh7FIe5LC45P4i4N0L7ob67UOVbhp6Nk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "B+UGsChLLZR7iqnt8yq91OgmTgwiUKTJhFxY4NT0O6c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X1uYwBCsCg1H+PnKdwtBqXlt0zKEURi8bOM940GcPfk=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xYOgT5l7shlNXCwHlguovmDkcEnF8dXyYlTyYrgZ8GE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "vFMTZqV8bh1+gcKzTkXweMddJlgdUnwX0DWzUUaMok4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4HI0y9FrtleZxZ7M6INdNhLelrQ2Rv/+ykWCBl+tMC8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jpJ0bBE474OUkn1vUiLWumIBtYmwc7J5+LQU/nyeLQc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jQTPeXZvdxY/DjtPfYfKUArIDsf0E9MVFy2O26sv1ec=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "QLLto0ExR2ZYMGqlyaMZc/hXFFTlwmgtKbiVq/xJIeI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yBJNviU1nchbGbhx6InXCVRXa90sEepz1EwbYuKXu2U=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jpEf0vHxrPu9gTJutNXSi2g/2Mc4WXFEN7yHonZEb7A=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "E09kLFckMYwNuhggMxmPtwndyvIAx+Vl+b2CV6FP75s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "N+ue6/cLPb5NssmJCCeo18LlbKPz6r2z20AsnTKRvOo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "yVQNZP8hhsvNGyDph2QP2qTNdXZTiIEVineKg+Qf33o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cSC9uI+9c5S8X+0G7amVyug1p0ZlgBsbEDYYyezBevQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1NpZGjoQzuQtekj80Rifxe9HbE08W07dfwxaFHaVn84=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "5Ghuq/8l11Ug9Uf/RTwf9On3OxOwIXUcb9soiy4J7/w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0LWKaEty6ywxLFhDaAqulqfMnYc+tgPfH4apyEeKg80=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "OwSthmCBtt6NIAoAh7aCbj82Yr/+9t8U7WuBQhFT3AQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "iYiyg6/1isqbMdvFPIGucu3cNM4NAZNtJhHpGZ4eM+c=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "waBgs8jWuGJPIF5zCRh6OmIyfK5GCBQgTMfmKSR2wyY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "1Jdtbe2BKJXPU2G9ywOrlODZ/cNYEQlKzAW3aMe1Hy4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xaLEnNUS/2ySerBpb9dN/D31t+wYcKekwTfkwtni0Mc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bIVBrOhOvr6cL55Tr24+B+CC9MiG7U6K54aAr2IXXuw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6Cdq5wroGu2TEFnekuT7LhOpd/K/+PcipIljcHU9QL4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "K5l64vI4S/pLviLW6Pl0U3iQkI3ge0xg4RAHcEsyKJo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "bzhuvZ0Ls22yIOX+Hz51eAHlSuDbWR/e0u4EhfdpHbc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Qv+fr6uD4o0bZRp69QJCFL6zvn3G82c7L+N1IFzj7H0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "XAmISMbD3aEyQT+BQEphCKFNa0F0GDKFuhM9cGceKoQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4VLCokntMfm1AogpUnYGvhV7nllWSo3mS3hVESMy+hA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "xiXNLj/CipEH63Vb5cidi8q9X47EF4f3HtJSOH7mfM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "4XlCYfYBjI9XA5zOSgTiEBYcZsdwyXL+f5XtH2xUIOc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "k6DfQy7ZYJIkEly2B5hjOZznL4NcgMkllZjJLb7yq7w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ZzM6gwWesa3lxbZVZthpPFs2s3GV0RZREE2zOMhBRBo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "US+jeMeeOd7J0wR0efJtq2/18lcO8YFvhT4O3DeaonQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b6iSxiI1FM9SzxuG1bHqGA1i4+3GOi0/SPW00XB4L7o=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kn3LsxAVkzIZKK9I6fi0Cctr0yjXOYgaQWMCoj4hLpM=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json
new file mode 100644
index 000000000..f2ea49ad7
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json
@@ -0,0 +1,586 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DoublePrecision. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$gt": {
+                      "$numberDouble": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedDoublePrecision": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mVZb+Ra0EYjQ4Zrh9X//E2T8MRj7NMqm5GUJXhRrBEI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MgwakFvPyBlwqFTbhWUF79URJQWFoJTGotlEVSPPUsQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DyBERpMSD5lEM5Nhpcn4WGgxgn/mkUVJp+PYSLX5jsE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I43iazc0xj1WVbYB/V+uTL/tughN1bBlxh1iypBnNsA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wjOBa/ATMuOywFmuPgC0GF/oeLqu0Z7eK5udzkTPbis=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gRQVwiR+m+0Vg8ZDXqrQQcVnTyobwCXNaA4BCJVXtMc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WUZ6huwx0ZbLb0R00uiC9FOJzsUocUN8qE5+YRenkvQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7s79aKEuPgQcS/YPOOVcYNZvHIo7FFsWtFCrnDKXefA=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json
new file mode 100644
index 000000000..e69d91269
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json
@@ -0,0 +1,1650 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "0.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gte": {
+                  "$numberDouble": "0.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "1.0"
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$lt": {
+                  "$numberDouble": "1.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$lte": {
+                  "$numberDouble": "1.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$lt": {
+                  "$numberDouble": "0.0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "200.0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be less than the range max"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "0.0"
+                },
+                "$lt": {
+                  "$numberDouble": "2.0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gte": {
+                  "$numberDouble": "0.0"
+                },
+                "$lte": {
+                  "$numberDouble": "200.0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$in": [
+                  {
+                    "$numberDouble": "0.0"
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Insert out of range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "-1"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "value must be greater than or equal to the minimum value"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Insert min and max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 200,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "200.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {},
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 200,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "200.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$gte": {
+                      "$numberDouble": "0.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$gt": {
+                      "$numberDouble": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$lt": {
+                      "$numberDouble": "1.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$lte": {
+                      "$numberDouble": "1.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$lt": {
+                      "$numberDouble": "0.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$gt": {
+                      "$numberDouble": "200.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be less than the range max"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$gt": {
+                      "$numberDouble": "0.0"
+                    },
+                    "$lt": {
+                      "$numberDouble": "2.0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$numberDouble": "0.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$numberDouble": "1.0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$gte": {
+                      "$numberDouble": "0.0"
+                    },
+                    "$lte": {
+                      "$numberDouble": "200.0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1.0"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedDoublePrecision": {
+                    "$in": [
+                      {
+                        "$numberDouble": "0.0"
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0.0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberInt": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Int",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gte": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json
new file mode 100644
index 000000000..d6a9c4b7e
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json
@@ -0,0 +1,491 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DoublePrecision. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedDoublePrecision": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDoublePrecision": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json
new file mode 100644
index 000000000..0511c2e37
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json
@@ -0,0 +1,608 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DoublePrecision. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDoublePrecision": {
+                  "$numberDouble": "2"
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedDoublePrecision": {
+              "$numberDouble": "1"
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedDoublePrecision": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDoublePrecision": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "V6knyt7Zq2CG3++l75UtBx2m32iGAPjHiAe439Bf02w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0OKSXELxPP85SBVwDGf3LtMEQCJ8TTkFUl/+6jlkdb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uEw0lpQtBppR3vqV9j9+NQRSBF1BzZukb8c9IhyWvxc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zVhZ7Q59O087ji49oMJvBIgeir2oqvUpnh4p53GcTow=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dowrzKs+qJhRMZyKDbhjXbuX43FbmUKOaw9I8YlOZDw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ep5B6cska6THLIF7Mn3tn3RvV9EiwLSt0eZM/CLRUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "URNp/YmmDh5wIZUfAzzgPyJeMNiVx9PMsz52DZRujGY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wlM4IAQhhKQEzoVqS8b1Ddd50GB95OFb9LnzOwyjCP4=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json
new file mode 100644
index 000000000..616101b4d
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json
@@ -0,0 +1,577 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DoublePrecision. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedDoublePrecision": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "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",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "mVZb+Ra0EYjQ4Zrh9X//E2T8MRj7NMqm5GUJXhRrBEI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "MgwakFvPyBlwqFTbhWUF79URJQWFoJTGotlEVSPPUsQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "DyBERpMSD5lEM5Nhpcn4WGgxgn/mkUVJp+PYSLX5jsE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "I43iazc0xj1WVbYB/V+uTL/tughN1bBlxh1iypBnNsA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wjOBa/ATMuOywFmuPgC0GF/oeLqu0Z7eK5udzkTPbis=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "gRQVwiR+m+0Vg8ZDXqrQQcVnTyobwCXNaA4BCJVXtMc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "WUZ6huwx0ZbLb0R00uiC9FOJzsUocUN8qE5+YRenkvQ=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "7s79aKEuPgQcS/YPOOVcYNZvHIo7FFsWtFCrnDKXefA=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json
new file mode 100644
index 000000000..300202e22
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json
@@ -0,0 +1,612 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range DoublePrecision. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$numberDouble": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedDoublePrecision": {
+                "$gt": {
+                  "$numberDouble": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedDoublePrecision": {
+                  "$numberDouble": "2"
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedDoublePrecision": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedDoublePrecision": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "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",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedDoublePrecision": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedDoublePrecision",
+                        "bsonType": "double",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberDouble": "0.0"
+                          },
+                          "max": {
+                            "$numberDouble": "200.0"
+                          },
+                          "precision": {
+                            "$numberInt": "2"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedDoublePrecision": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Dri0CXmL78L2DOgk9w0DwxHOMGMzih7m6l59vgy+WWo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "b7d8mRzD1kI1tdc7uNL+YAUonJ6pODLsRLkArfEKSkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "Xg8C1/A0KJaXOw4i+26Rv03/CydaaunOzXh0CIT+gn8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "UoKUDw2wJYToUCcFaIs03YQSTksYR0MIOTJllwODqKc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "c/5cwAT0C5jber2xlJnWD3a5tVDy0nRtr5HG02hoFOY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wSUrRXavAGaajNeqC5mEUH1K67oYl5Wy9RNIzKjwLAM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6vrp4wWDtHEgHWR99I70WVDzevg1Fk/Pw5U8gUDa0OU=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedDoublePrecision": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "V6knyt7Zq2CG3++l75UtBx2m32iGAPjHiAe439Bf02w=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "0OKSXELxPP85SBVwDGf3LtMEQCJ8TTkFUl/+6jlkdb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uEw0lpQtBppR3vqV9j9+NQRSBF1BzZukb8c9IhyWvxc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zVhZ7Q59O087ji49oMJvBIgeir2oqvUpnh4p53GcTow=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "dowrzKs+qJhRMZyKDbhjXbuX43FbmUKOaw9I8YlOZDw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ep5B6cska6THLIF7Mn3tn3RvV9EiwLSt0eZM/CLRUDc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "URNp/YmmDh5wIZUfAzzgPyJeMNiVx9PMsz52DZRujGY=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "wlM4IAQhhKQEzoVqS8b1Ddd50GB95OFb9LnzOwyjCP4=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json
new file mode 100644
index 000000000..536415f3f
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json
@@ -0,0 +1,490 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Int. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$gt": {
+                      "$numberInt": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedInt": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json
new file mode 100644
index 000000000..6abd773da
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json
@@ -0,0 +1,1644 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gte": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "1"
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$lt": {
+                  "$numberInt": "1"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$lte": {
+                  "$numberInt": "1"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$lt": {
+                  "$numberInt": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "200"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be less than the range maximum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "0"
+                },
+                "$lt": {
+                  "$numberInt": "2"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gte": {
+                  "$numberInt": "0"
+                },
+                "$lte": {
+                  "$numberInt": "200"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$in": [
+                  {
+                    "$numberInt": "0"
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Insert out of range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "-1"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "value must be greater than or equal to the minimum value"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Insert min and max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 200,
+              "encryptedInt": {
+                "$numberInt": "200"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {},
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 200,
+              "encryptedInt": {
+                "$numberInt": "200"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$gte": {
+                      "$numberInt": "0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$gt": {
+                      "$numberInt": "1"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$lt": {
+                      "$numberInt": "1"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$lte": {
+                      "$numberInt": "1"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$lt": {
+                      "$numberInt": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$gt": {
+                      "$numberInt": "200"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be less than the range maximum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$gt": {
+                      "$numberInt": "0"
+                    },
+                    "$lt": {
+                      "$numberInt": "2"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$numberInt": "0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$numberInt": "1"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$gte": {
+                      "$numberInt": "0"
+                    },
+                    "$lte": {
+                      "$numberInt": "200"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedInt": {
+                    "$in": [
+                      {
+                        "$numberInt": "0"
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberDouble": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gte": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json
new file mode 100644
index 000000000..9d5bff1d1
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json
@@ -0,0 +1,437 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Int. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedInt": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedInt": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json
new file mode 100644
index 000000000..4bf57700c
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json
@@ -0,0 +1,512 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Int. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedInt": {
+                  "$numberInt": "2"
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedInt": {
+              "$numberInt": "1"
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedInt": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedInt": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hyDcE6QQjPrYJaIS/n7evEZFYcm31Tj89CpEYGF45cI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ty4cnzJdAlbQKnh7px3GEYjBnvO+jIOaKjoTRDtmh3M=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json
new file mode 100644
index 000000000..6f6022e74
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json
@@ -0,0 +1,481 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Int. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedInt": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json
new file mode 100644
index 000000000..17d23b957
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json
@@ -0,0 +1,516 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Int. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedInt": {
+                "$numberInt": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gt": {
+                  "$numberInt": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedInt": {
+                  "$numberInt": "2"
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedInt": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedInt": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedInt": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedInt",
+                        "bsonType": "int",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberInt": "0"
+                          },
+                          "max": {
+                            "$numberInt": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedInt": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedInt": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hyDcE6QQjPrYJaIS/n7evEZFYcm31Tj89CpEYGF45cI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ty4cnzJdAlbQKnh7px3GEYjBnvO+jIOaKjoTRDtmh3M=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json
new file mode 100644
index 000000000..3f1c723bd
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json
@@ -0,0 +1,490 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Long. Aggregate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$gt": {
+                      "$numberLong": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "aggregate": "default",
+              "pipeline": [
+                {
+                  "$match": {
+                    "encryptedLong": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  }
+                }
+              ],
+              "cursor": {},
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "aggregate"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json
new file mode 100644
index 000000000..972388c6c
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json
@@ -0,0 +1,1644 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Find with $gt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gte": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$lt": {
+                  "$numberLong": "1"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$lte": {
+                  "$numberLong": "1"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$lt": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "200"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "must be less than the range maximum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Find with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "0"
+                },
+                "$lt": {
+                  "$numberLong": "2"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gte": {
+                  "$numberLong": "0"
+                },
+                "$lte": {
+                  "$numberLong": "200"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Find with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$in": [
+                  {
+                    "$numberLong": "0"
+                  }
+                ]
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Insert out of range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "-1"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "value must be greater than or equal to the minimum value"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Insert min and max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 200,
+              "encryptedLong": {
+                "$numberLong": "200"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {},
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 200,
+              "encryptedLong": {
+                "$numberLong": "200"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$gte": {
+                      "$numberLong": "0"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt with no results",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$gt": {
+                      "$numberLong": "1"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": []
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$lt": {
+                      "$numberLong": "1"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lte",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$lte": {
+                      "$numberLong": "1"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $lt below min",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$lt": {
+                      "$numberLong": "0"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be greater than the range minimum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt above max",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$gt": {
+                      "$numberLong": "200"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": {
+            "errorContains": "must be less than the range maximum"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $gt and $lt",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$gt": {
+                      "$numberLong": "0"
+                    },
+                    "$lt": {
+                      "$numberLong": "2"
+                    }
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with equality",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$numberLong": "0"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          ]
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$numberLong": "1"
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with full range",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$gte": {
+                      "$numberLong": "0"
+                    },
+                    "$lte": {
+                      "$numberLong": "200"
+                    }
+                  }
+                }
+              },
+              {
+                "$sort": {
+                  "_id": 1
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Aggregate with $in",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "aggregate",
+          "arguments": {
+            "pipeline": [
+              {
+                "$match": {
+                  "encryptedLong": {
+                    "$in": [
+                      {
+                        "$numberLong": "0"
+                      }
+                    ]
+                  }
+                }
+              }
+            ]
+          },
+          "result": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Insert Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberDouble": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gte": {
+                  "$numberDouble": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json
new file mode 100644
index 000000000..89e189840
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json
@@ -0,0 +1,437 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Long. Delete.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "deleteOne",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          },
+          "result": {
+            "deletedCount": 1
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "delete": "default",
+              "deletes": [
+                {
+                  "q": {
+                    "encryptedLong": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "limit": 1
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedLong": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "delete"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json
new file mode 100644
index 000000000..59342a343
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json
@@ -0,0 +1,512 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Long. FindOneAndUpdate.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedLong": {
+                  "$numberLong": "2"
+                }
+              }
+            },
+            "returnDocument": "Before"
+          },
+          "result": {
+            "_id": 1,
+            "encryptedLong": {
+              "$numberLong": "1"
+            }
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "findAndModify": "default",
+              "query": {
+                "encryptedLong": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "update": {
+                "$set": {
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedLong": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            },
+            "command_name": "findAndModify"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hyDcE6QQjPrYJaIS/n7evEZFYcm31Tj89CpEYGF45cI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ty4cnzJdAlbQKnh7px3GEYjBnvO+jIOaKjoTRDtmh3M=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json
new file mode 100644
index 000000000..882e52170
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json
@@ -0,0 +1,481 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Long. Insert and Find.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "0"
+                }
+              }
+            }
+          },
+          "result": [
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          ]
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "default",
+              "filter": {
+                "encryptedLong": {
+                  "$gt": {
+                    "$binary": {
+                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "subType": "06"
+                    }
+                  }
+                }
+              },
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "find"
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "bE1vqWj3KNyM7cCYUv/cnYm8BPaUL3eMp5syTHq6NF4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "25j9sQXZCihCmHKvTHgaBsAVZFcGPn7JjHdrCGlwyyw=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FA74j21GUEJb1DJBOpR9nVnjaDZnd8yAQNuaW9Qi26g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kJv//KVkbrobIBf+QeWC5jxn20mx/P0R1N6aCSMgKM8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "zB+Whi9IUUGxfLEe+lGuIzLX4LFbIhaIAm5lRk65QTc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ybO1QU3CgvhO8JgRXH+HxKszWcpl5aGDYYVa75fHa1g=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "X3Y3eSAbbMg//JgiHHiFpYOpV61t8kkDexI+CQyitH4=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "SlNHXyqVFGDPrX/2ppwog6l4pwj3PKda2TkZbqgfSfA=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "McjV8xwTF3xI7863DYOBdyvIv6UpzThl6v9vBRk05bI=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json
new file mode 100644
index 000000000..92e3e390a
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json
@@ -0,0 +1,516 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "FLE2 Range Long. Update.",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedLong": {
+                "$numberLong": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 1,
+              "encryptedLong": {
+                "$numberLong": "1"
+              }
+            }
+          }
+        },
+        {
+          "name": "updateOne",
+          "arguments": {
+            "filter": {
+              "encryptedLong": {
+                "$gt": {
+                  "$numberLong": "0"
+                }
+              }
+            },
+            "update": {
+              "$set": {
+                "encryptedLong": {
+                  "$numberLong": "2"
+                }
+              }
+            }
+          },
+          "result": {
+            "matchedCount": 1,
+            "modifiedCount": 1,
+            "upsertedCount": 0
+          }
+        }
+      ],
+      "expectations": [
+        {
+          "command_started_event": {
+            "command": {
+              "listCollections": 1,
+              "filter": {
+                "name": "default"
+              }
+            },
+            "command_name": "listCollections"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "find": "datakeys",
+              "filter": {
+                "$or": [
+                  {
+                    "_id": {
+                      "$in": [
+                        {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        }
+                      ]
+                    }
+                  },
+                  {
+                    "keyAltNames": {
+                      "$in": []
+                    }
+                  }
+                ]
+              },
+              "$db": "keyvault",
+              "readConcern": {
+                "level": "majority"
+              }
+            },
+            "command_name": "find"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 0,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command": {
+              "insert": "default",
+              "documents": [
+                {
+                  "_id": 1,
+                  "encryptedLong": {
+                    "$$type": "binData"
+                  }
+                }
+              ],
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                }
+              }
+            },
+            "command_name": "insert"
+          }
+        },
+        {
+          "command_started_event": {
+            "command_name": "update",
+            "command": {
+              "update": "default",
+              "ordered": true,
+              "updates": [
+                {
+                  "q": {
+                    "encryptedLong": {
+                      "$gt": {
+                        "$binary": {
+                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "subType": "06"
+                        }
+                      }
+                    }
+                  },
+                  "u": {
+                    "$set": {
+                      "encryptedLong": {
+                        "$$type": "binData"
+                      }
+                    }
+                  }
+                }
+              ],
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "eccCollection": "enxcol_.default.ecc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedLong",
+                        "bsonType": "long",
+                        "queries": {
+                          "queryType": "rangePreview",
+                          "contention": {
+                            "$numberLong": "0"
+                          },
+                          "sparsity": {
+                            "$numberLong": "1"
+                          },
+                          "min": {
+                            "$numberLong": "0"
+                          },
+                          "max": {
+                            "$numberLong": "200"
+                          }
+                        }
+                      }
+                    ]
+                  }
+                },
+                "deleteTokens": {
+                  "default.default": {
+                    "encryptedLong": {
+                      "e": {
+                        "$binary": {
+                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
+                          "subType": "00"
+                        }
+                      },
+                      "o": {
+                        "$binary": {
+                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
+                          "subType": "00"
+                        }
+                      }
+                    }
+                  }
+                }
+              },
+              "$db": "default"
+            }
+          }
+        }
+      ],
+      "outcome": {
+        "collection": {
+          "data": [
+            {
+              "_id": 0,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "5nRutVIyq7URVOVtbE4vM01APSIajAVnsShMwjBlzkM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "RjBYT2h3ZAoHxhf8DU6/dFbDkEBZp0IxREcsRTu2MXs=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "x7GR49EN0t3WXQDihkrbonK7qNIBYC87tpL/XEUyIYc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "JfYUqWF+OoGjiYkRI4L5iPlF+T1Eleul7Fki22jp4Qc=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "q1RyGfIgsaQHoZFRw+DD28V26rN5hweApPLwExncvT8=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "L2PFeKGvLS6C+DLudR6fGlBq3ERPvjWvRyNRIA2HVb0=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "CWxaNqL3iP1yCixDkcmf9bmW3E5VeN8TJkg1jJe528s=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "+vC6araOEo+fpW7PSIP40/EnzBCj1d2N10Jr3rrXJJM=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "6SV63Mf51Z6A6p2X3rCnJKCu6ku3Oeb45mBYbz+IoAo=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            },
+            {
+              "_id": 1,
+              "encryptedLong": {
+                "$$type": "binData"
+              },
+              "__safeContent__": [
+                {
+                  "$binary": {
+                    "base64": "DLCAJs+W2PL2DV5YChCL6dYrQNr+j4p3L7xhVaub4ic=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "hyDcE6QQjPrYJaIS/n7evEZFYcm31Tj89CpEYGF45cI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "F08nMDWDZc+DbWM7XCEJNNCEYyinRmrvGP7EWhmp4is=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "cXH4688amcDc8kZOJq4UP8cE3R58Zl7e+Qo/1jyspps=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "uURBxvTp3FBCVkd+LPqyuY7d6rMW6SGIJQEPY/wtkZI=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "jG3hax1L3RBp9t38vUt53FsBxgr/+Si/vVISpAylYpE=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "kwtIW8MhH9Ky5xNjBx8gFA/SHh2YVphie7g5FGBzals=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "FHflwFuEMu4xX0ZApHi+pdlBH+oevAtXckCUb5Wv0xU=",
+                    "subType": "00"
+                  }
+                },
+                {
+                  "$binary": {
+                    "base64": "ty4cnzJdAlbQKnh7px3GEYjBnvO+jIOaKjoTRDtmh3M=",
+                    "subType": "00"
+                  }
+                }
+              ]
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json b/tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json
new file mode 100644
index 000000000..9eddf1c99
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json
@@ -0,0 +1,162 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.2.0",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "data": [],
+  "encrypted_fields": {
+    "escCollection": "enxcol_.default.esc",
+    "eccCollection": "enxcol_.default.ecc",
+    "ecocCollection": "enxcol_.default.ecoc",
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "contention": {
+            "$numberLong": "0"
+          },
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  },
+  "key_vault_data": [
+    {
+      "_id": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "keyMaterial": {
+        "$binary": {
+          "base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
+          "subType": "00"
+        }
+      },
+      "creationDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "updateDate": {
+        "$date": {
+          "$numberLong": "1648914851981"
+        }
+      },
+      "status": {
+        "$numberInt": "0"
+      },
+      "masterKey": {
+        "provider": "local"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "Wrong type: Insert Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberDouble": "0"
+              }
+            }
+          },
+          "result": {
+            "errorContains": "cannot encrypt element"
+          }
+        }
+      ]
+    },
+    {
+      "description": "Wrong type: Find Double",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "local": {
+              "key": {
+                "$binary": {
+                  "base64": "Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk",
+                  "subType": "00"
+                }
+              }
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "insertOne",
+          "arguments": {
+            "document": {
+              "_id": 0,
+              "encryptedInt": {
+                "$numberInt": "0"
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "arguments": {
+            "filter": {
+              "encryptedInt": {
+                "$gte": {
+                  "$numberDouble": "0"
+                }
+              }
+            },
+            "sort": {
+              "_id": 1
+            }
+          },
+          "result": {
+            "errorContains": "field type is not supported"
+          }
+        }
+      ]
+    }
+  ]
+}

From 2dd2e84047a0c86ac564fd9c8303b39770edabf5 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Wed, 22 Mar 2023 17:14:02 +0800
Subject: [PATCH 267/321] PHPLIB-1093: Assert $expectedType array is non-empty
 for InvalidArgumentException (#1049)

* PHPLIB-1093: Assert $expectedType array is non-empty for InvalidArgumentException

This also factors out the logic for converting an $expectedType array to a string.

Co-authored-by: Andreas Braun 
---
 phpunit.evergreen.xml                         |  2 +
 phpunit.xml.dist                              |  2 +
 src/Exception/InvalidArgumentException.php    | 38 +++++++--------
 .../InvalidArgumentExceptionTest.php          | 48 +++++++++++++++++++
 4 files changed, 71 insertions(+), 19 deletions(-)
 create mode 100644 tests/Exception/InvalidArgumentExceptionTest.php

diff --git a/phpunit.evergreen.xml b/phpunit.evergreen.xml
index b157e92c4..da26eba50 100644
--- a/phpunit.evergreen.xml
+++ b/phpunit.evergreen.xml
@@ -11,8 +11,10 @@
 >
 
     
+        
         
         
+        
         
         
     
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index d5ec557d1..f8a13387c 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -11,7 +11,9 @@
 >
 
     
+        
         
+        
         
         
     
diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php
index 34f4cc5d9..890eb6c16 100644
--- a/src/Exception/InvalidArgumentException.php
+++ b/src/Exception/InvalidArgumentException.php
@@ -20,6 +20,7 @@
 use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
 
 use function array_pop;
+use function assert;
 use function count;
 use function get_debug_type;
 use function implode;
@@ -31,32 +32,31 @@ class InvalidArgumentException extends DriverInvalidArgumentException implements
     /**
      * Thrown when an argument or option has an invalid type.
      *
-     * @param string          $name         Name of the argument or option
-     * @param mixed           $value        Actual value (used to derive the type)
-     * @param string|string[] $expectedType Expected type
+     * @param string              $name         Name of the argument or option
+     * @param mixed               $value        Actual value (used to derive the type)
+     * @param string|list $expectedType Expected type as a string or an array containing one or more strings
      * @return self
      */
     public static function invalidType(string $name, $value, $expectedType)
     {
         if (is_array($expectedType)) {
-            switch (count($expectedType)) {
-                case 1:
-                    $typeString = array_pop($expectedType);
-                    break;
-
-                case 2:
-                    $typeString = implode('" or "', $expectedType);
-                    break;
-
-                default:
-                    $lastType = array_pop($expectedType);
-                    $typeString = sprintf('%s", or "%s', implode('", "', $expectedType), $lastType);
-                    break;
-            }
-
-            $expectedType = $typeString;
+            $expectedType = self::expectedTypesToString($expectedType);
         }
 
         return new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, get_debug_type($value)));
     }
+
+    /** @param list $types */
+    private static function expectedTypesToString(array $types): string
+    {
+        assert(count($types) > 0);
+
+        if (count($types) < 3) {
+            return implode('" or "', $types);
+        }
+
+        $lastType = array_pop($types);
+
+        return sprintf('%s", or "%s', implode('", "', $types), $lastType);
+    }
 }
diff --git a/tests/Exception/InvalidArgumentExceptionTest.php b/tests/Exception/InvalidArgumentExceptionTest.php
new file mode 100644
index 000000000..0052c77b0
--- /dev/null
+++ b/tests/Exception/InvalidArgumentExceptionTest.php
@@ -0,0 +1,48 @@
+assertStringContainsString($typeString, $e->getMessage());
+    }
+
+    public function provideExpectedTypes()
+    {
+        yield 'expectedType is a string' => [
+            'array',
+            'type "array"',
+        ];
+
+        yield 'expectedType is an array with one string' => [
+            ['array'],
+            'type "array"',
+        ];
+
+        yield 'expectedType is an array with two strings' => [
+            ['array', 'integer'],
+            'type "array" or "integer"',
+        ];
+
+        yield 'expectedType is an array with three strings' => [
+            ['array', 'integer', 'object'],
+            'type "array", "integer", or "object"',
+        ];
+    }
+
+    public function testExpectedTypeArrayMustNotBeEmpty(): void
+    {
+        $this->expectException(AssertionError::class);
+        InvalidArgumentException::invalidType('$arg', null, []);
+    }
+}

From 446985d7d5fc1bc297b2394e5405bfb44f0b09fc Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 28 Mar 2023 22:42:02 +0800
Subject: [PATCH 268/321] PHPLIB-1094: Remove obsolete internal constants
 (#1052)

---
 src/Operation/EstimatedDocumentCount.php | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php
index 6deeef3e5..dc91a27ac 100644
--- a/src/Operation/EstimatedDocumentCount.php
+++ b/src/Operation/EstimatedDocumentCount.php
@@ -47,12 +47,6 @@ class EstimatedDocumentCount implements Executable, Explainable
     /** @var array */
     private $options;
 
-    /** @var int */
-    private static $errorCodeCollectionNotFound = 26;
-
-    /** @var int */
-    private static $wireVersionForCollStats = 12;
-
     /**
      * Constructs a command to get the estimated number of documents in a
      * collection.

From 5cb1631b7ab61ea9964643ff39d1ad3b519ac1d0 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 11 Apr 2023 15:12:44 +0800
Subject: [PATCH 269/321] PHPLIB-1095: Queryable Encryption is "Public
 Technical Preview" (#1053)

This note was originally missed when introducing QE-related APIs in PHPLIB 1.13.
---
 ...gs-MongoDBDatabase-method-createCollection-option.yaml | 8 ++++++++
 docs/includes/apiargs-dropCollection-option.yaml          | 8 ++++++++
 docs/tutorial/client-side-encryption.txt                  | 6 +++++-
 3 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
index f95b406c2..a970a3989 100644
--- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
+++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
@@ -89,6 +89,14 @@ description: |
   This option is available in MongoDB 6.0+ and will result in an exception at
   execution time if specified for an older server version.
 
+  .. note::
+
+     Queryable Encryption is in public preview and available for evaluation
+     purposes. It is not yet recommended for production deployments as breaking
+     changes may be introduced. See the
+     `Queryable Encryption Preview `_
+     blog post for more information.
+
   .. versionadded:: 1.13
 interface: phpmethod
 operation: ~
diff --git a/docs/includes/apiargs-dropCollection-option.yaml b/docs/includes/apiargs-dropCollection-option.yaml
index 018effa9e..29c945e60 100644
--- a/docs/includes/apiargs-dropCollection-option.yaml
+++ b/docs/includes/apiargs-dropCollection-option.yaml
@@ -9,6 +9,14 @@ description: |
   server-side value for ``encryptedFields``. See the
   `Client Side Encryption specification `_
   for more information.
+
+  .. note::
+
+     Queryable Encryption is in public preview and available for evaluation
+     purposes. It is not yet recommended for production deployments as breaking
+     changes may be introduced. See the
+     `Queryable Encryption Preview `_
+     blog post for more information.
 interface: phpmethod
 operation: ~
 optional: true
diff --git a/docs/tutorial/client-side-encryption.txt b/docs/tutorial/client-side-encryption.txt
index 6ed2e00d4..bd1d7ebd3 100644
--- a/docs/tutorial/client-side-encryption.txt
+++ b/docs/tutorial/client-side-encryption.txt
@@ -248,7 +248,11 @@ Automatic Queryable Encryption
 .. note::
 
    Automatic queryable encryption is an enterprise only feature and requires
-   MongoDB 6.0+.
+   MongoDB 6.0+. Queryable Encryption is in public preview and available for
+   evaluation purposes. It is not yet recommended for production deployments as
+   breaking changes may be introduced. See the
+   `Queryable Encryption Preview `_
+   blog post for more information.
 
 The following example uses a local key; however, other key providers such as AWS
 are also an option. The data in the ``encryptedIndexed`` and

From 94e8b16a1b21d69776f82136facfd19b87e60833 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 11 Apr 2023 15:31:01 +0800
Subject: [PATCH 270/321] Update docs for encryptedFields create/drop
 collection option (#1054)

The MongoDB manual reference is more helpful than the CSFLE specification. Additionally, clarify how the option is used by the drop collection helpers.
---
 ...ngoDBDatabase-method-createCollection-option.yaml |  6 +++---
 docs/includes/apiargs-dropCollection-option.yaml     | 12 +++++++++---
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
index 063b84c4b..f40cbf94b 100644
--- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
+++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
@@ -82,9 +82,9 @@ type: document
 description: |
   A document describing encrypted fields for queryable encryption. If omitted,
   the ``encryptedFieldsMap`` option within the ``autoEncryption`` driver option
-  will be consulted. See the
-  `Client Side Encryption specification `_
-  for more information.
+  will be consulted. See
+  `Field Encryption and Queryability `_
+  in the MongoDB manual for more information.
 
   This option is available in MongoDB 6.0+ and will result in an exception at
   execution time if specified for an older server version.
diff --git a/docs/includes/apiargs-dropCollection-option.yaml b/docs/includes/apiargs-dropCollection-option.yaml
index 29c945e60..46ad66075 100644
--- a/docs/includes/apiargs-dropCollection-option.yaml
+++ b/docs/includes/apiargs-dropCollection-option.yaml
@@ -6,9 +6,15 @@ description: |
   the ``encryptedFieldsMap`` option within the ``autoEncryption`` driver option
   will be consulted. If ``encryptedFieldsMap`` was defined but does not specify
   this collection, the library will make a final attempt to consult the
-  server-side value for ``encryptedFields``. See the
-  `Client Side Encryption specification `_
-  for more information.
+  server-side value for ``encryptedFields``. See
+  `Field Encryption and Queryability `_
+  in the MongoDB manual for more information.
+
+  .. note::
+
+     This option is not passed to the :manual:`drop `
+     command. The library uses it to determine related metadata collections that
+     should be dropped in addition to an encrypted collection.
 
   .. note::
 

From 40678441f75ed5e95e5ead8a67ed639020b59447 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 11 Apr 2023 16:29:41 +0800
Subject: [PATCH 271/321] PHPLIB-1099: Add MongoDB rapid releases to Evergreen
 matrix (#1056)

* Add rapid to mongodb-versions axis

* Add rapid and latest to requireApiVersion and loadBalanced matrices

* Rename VERSION to MONGODB_VERSION

* Test skip_crypt_shared and without_aws_creds on more server versions
---
 .evergreen/config.yml | 50 +++++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 18 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index be1192e6a..76f1f6695 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -175,7 +175,7 @@ functions:
       params:
         script: |
           ${PREPARE_SHELL}
-          MONGODB_VERSION=${VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} LOAD_BALANCER=${LOAD_BALANCER} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh
+          MONGODB_VERSION=${MONGODB_VERSION} ORCHESTRATION_FILE=${ORCHESTRATION_FILE} TOPOLOGY=${TOPOLOGY} AUTH=${AUTH} SSL=${SSL} STORAGE_ENGINE=${STORAGE_ENGINE} LOAD_BALANCER=${LOAD_BALANCER} REQUIRE_API_VERSION=${REQUIRE_API_VERSION} sh ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh
     # run-orchestration generates expansion file with MONGODB_URI and CRYPT_SHARED_LIB_PATH
     - command: expansions.update
       params:
@@ -708,31 +708,35 @@ axes:
       - id: "latest"
         display_name: "MongoDB latest"
         variables:
-           VERSION: "latest"
+           MONGODB_VERSION: "latest"
+      - id: "rapid"
+        display_name: "MongoDB rapid"
+        variables:
+           MONGODB_VERSION: "rapid"
       - id: "6.0"
         display_name: "MongoDB 6.0"
         variables:
-           VERSION: "6.0"
+           MONGODB_VERSION: "6.0"
       - id: "5.0"
         display_name: "MongoDB 5.0"
         variables:
-           VERSION: "5.0"
+           MONGODB_VERSION: "5.0"
       - id: "4.4"
         display_name: "MongoDB 4.4"
         variables:
-           VERSION: "4.4"
+           MONGODB_VERSION: "4.4"
       - id: "4.2"
         display_name: "MongoDB 4.2"
         variables:
-           VERSION: "4.2"
+           MONGODB_VERSION: "4.2"
       - id: "4.0"
         display_name: "MongoDB 4.0"
         variables:
-           VERSION: "4.0"
+           MONGODB_VERSION: "4.0"
       - id: "3.6"
         display_name: "MongoDB 3.6"
         variables:
-           VERSION: "3.6"
+           MONGODB_VERSION: "3.6"
 
   - id: mongodb-edge-versions
     display_name: MongoDB Version
@@ -740,11 +744,11 @@ axes:
       - id: "latest-stable"
         display_name: "MongoDB 6.0"
         variables:
-          VERSION: "6.0"
+          MONGODB_VERSION: "6.0"
       - id: "oldest-supported"
         display_name: "MongoDB 3.6"
         variables:
-          VERSION: "3.6"
+          MONGODB_VERSION: "3.6"
 
   - id: driver-versions
     display_name: Driver Version
@@ -872,7 +876,7 @@ buildvariants:
   display_name: "${os}, ${mongodb-versions}, ${php-edge-versions}, ${driver-versions}"
   exclude_spec:
     # Debian 9.2 only supports up to MongoDB 5.0
-    - { "os": "debian92", "mongodb-versions": ["6.0", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+    - { "os": "debian92", "mongodb-versions": ["6.0", "rapid", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
     - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4", "5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   tasks:
     - name: "test-standalone"
@@ -897,10 +901,12 @@ buildvariants:
   tasks:
     - name: "test-atlas-data-lake"
 
-# Stable API is available from MongoDB 5.0+
 - matrix_name: "test-requireApiVersion"
-  matrix_spec: { "os": "debian11", "mongodb-versions": ["5.0", "6.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+  matrix_spec: { "os": "debian11", "mongodb-versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   display_name: "Versioned API - ${mongodb-versions}"
+  exclude_spec:
+    # Stable API is available from MongoDB 5.0+
+    - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   tasks:
     - .versioned-api
 
@@ -910,23 +916,31 @@ buildvariants:
   tasks:
     - .serverless
 
-# Load balancer is available from MongoDB 5.0+
 - matrix_name: "test-loadBalanced"
-  matrix_spec: { "os": "debian11", "mongodb-versions": ["5.0", "6.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+  matrix_spec: { "os": "debian11", "mongodb-versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   display_name: "Load balanced - ${mongodb-versions}"
+  exclude_spec:
+    # Load balancer is available from MongoDB 5.0+
+    - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   tasks:
     - name: "test-loadBalanced"
 
-# CSFLE crypt_shared is available from MongoDB 6.0+, so explicitly test without it to allow use of mongocryptd
 - matrix_name: "test-csfle-skip_crypt_shared"
-  matrix_spec: { "os": "debian11", "mongodb-versions": "6.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+  matrix_spec: { "os": "debian11", "mongodb-versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   display_name: "CSFLE skip_crypt_shared - ${mongodb-versions}"
+  exclude_spec:
+    # CSFLE crypt_shared is available from MongoDB 6.0+
+    - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4", "5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   tasks:
     - name: "test-skip_crypt_shared"
 
 # Run CSFLE tests without AWS credentials (for "On-demand AWS Credentials" prose test)
 - matrix_name: "test-csfle-without_aws_creds"
-  matrix_spec: { "os": "debian11", "mongodb-versions": "6.0", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+  matrix_spec: { "os": ["debian92", "debian11"], "mongodb-versions": "*", "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   display_name: "CSFLE without_aws_creds - ${mongodb-versions}"
+  exclude_spec:
+    # CSFLE is available from MongoDB 4.2+ and Debian 9.2 only supports up to MongoDB 5.0
+    - { "os": "debian92", "mongodb-versions": ["3.6", "4.0", "6.0", "rapid", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+    - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4", "5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   tasks:
     - name: "test-without_aws_creds"

From b96382129b61c74864e70b112808a8795db33663 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Wed, 12 Apr 2023 12:03:32 +0800
Subject: [PATCH 272/321] PHPLIB-913: Database::createEncryptedCollection()
 helper (#1050)

* Docs for Database::createEncryptedCollection()

* Revise docs and require $options since encryptedFields is required

* Add example for creating new Client with auto encryption

* Permit coding standard deviations in CSFLE prose tests

* Extract Database methods to CreateEncryptedCollection operation

* Functional tests for CreateEncryptedCollection::createDataKeys()

* Test that createDataKey() doesn't modify encryptedFields object option

* Require replica sets for CreateEncryptedCollectionFunctionalTest

* Add reference links to CreateCollection operation docs

Co-authored-by: Andreas Braun 
---
 ...ethod-createEncryptedCollection-param.yaml |  47 +++++
 docs/reference/class/MongoDBDatabase.txt      |   1 +
 docs/reference/exception-classes.txt          |  15 ++
 ...goDBDatabase-createEncryptedCollection.txt | 144 +++++++++++++++
 phpcs.xml.dist                                |   4 +
 psalm-baseline.xml                            |   6 +
 src/Database.php                              |  76 ++++++--
 .../CreateEncryptedCollectionException.php    |  56 ++++++
 src/Operation/CreateCollection.php            |   3 +-
 src/Operation/CreateEncryptedCollection.php   | 167 +++++++++++++++++
 src/functions.php                             |  18 +-
 ...CreateEncryptedCollectionExceptionTest.php |  26 +++
 ...reateEncryptedCollectionFunctionalTest.php | 174 ++++++++++++++++++
 .../CreateEncryptedCollectionTest.php         |  34 ++++
 .../FunctionalTestCase.php                    | 130 +++++++++++++
 ...rose21_AutomaticDataEncryptionKeysTest.php | 171 +++++++++++++++++
 16 files changed, 1042 insertions(+), 30 deletions(-)
 create mode 100644 docs/includes/apiargs-MongoDBDatabase-method-createEncryptedCollection-param.yaml
 create mode 100644 docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt
 create mode 100644 src/Exception/CreateEncryptedCollectionException.php
 create mode 100644 src/Operation/CreateEncryptedCollection.php
 create mode 100644 tests/Exception/CreateEncryptedCollectionExceptionTest.php
 create mode 100644 tests/Operation/CreateEncryptedCollectionFunctionalTest.php
 create mode 100644 tests/Operation/CreateEncryptedCollectionTest.php
 create mode 100644 tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
 create mode 100644 tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php

diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createEncryptedCollection-param.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createEncryptedCollection-param.yaml
new file mode 100644
index 000000000..6d56d6785
--- /dev/null
+++ b/docs/includes/apiargs-MongoDBDatabase-method-createEncryptedCollection-param.yaml
@@ -0,0 +1,47 @@
+source:
+  file: apiargs-common-param.yaml
+  ref: $collectionName
+replacement:
+  subject: "encrypted collection"
+  action: " to create"
+---
+arg_name: param
+name: $clientEncryption
+type: :php:`MongoDB\\Driver\\ClientEncryption `
+description: |
+  The ClientEncryption object used to create data keys.
+interface: phpmethod
+operation: ~
+optional: false
+---
+arg_name: param
+name: $kmsProvider
+type: string
+description: |
+  KMS provider (e.g. "local", "aws") that will be used to encrypt new data keys.
+  This corresponds to the ``$kmsProvider`` parameter for
+  :php:`MongoDB\\Driver\\ClientEncryption::createDataKey() `.
+interface: phpmethod
+operation: ~
+optional: false
+---
+arg_name: param
+name: $masterKey
+type: array|null
+description: |
+  KMS-specific key options that will be used to encrypt new data keys. This
+  corresponds to the ``masterKey`` option for
+  :php:`MongoDB\\Driver\\ClientEncryption::createDataKey() `.
+
+  If ``$kmsProvider`` is "local", this should be ``null``.
+interface: phpmethod
+operation: ~
+optional: false
+---
+source:
+  file: apiargs-common-param.yaml
+  ref: $options
+optional: false
+post: |
+  The ``encryptedFields`` option is required.
+...
diff --git a/docs/reference/class/MongoDBDatabase.txt b/docs/reference/class/MongoDBDatabase.txt
index a4a7dd99d..ac0e0d16c 100644
--- a/docs/reference/class/MongoDBDatabase.txt
+++ b/docs/reference/class/MongoDBDatabase.txt
@@ -48,6 +48,7 @@ Methods
    /reference/method/MongoDBDatabase-aggregate
    /reference/method/MongoDBDatabase-command
    /reference/method/MongoDBDatabase-createCollection
+   /reference/method/MongoDBDatabase-createEncryptedCollection
    /reference/method/MongoDBDatabase-drop
    /reference/method/MongoDBDatabase-dropCollection
    /reference/method/MongoDBDatabase-getDatabaseName
diff --git a/docs/reference/exception-classes.txt b/docs/reference/exception-classes.txt
index b5f9fb0b6..20ae7067e 100644
--- a/docs/reference/exception-classes.txt
+++ b/docs/reference/exception-classes.txt
@@ -30,6 +30,21 @@ MongoDB\\Exception\\BadMethodCallException
 
 ----
 
+MongoDB\\Exception\\CreateEncryptedCollectionException
+------------------------------------------------------
+
+.. phpclass:: MongoDB\\Exception\\CreateEncryptedCollectionException
+
+   Thrown by :phpmethod:`MongoDB\\Database::createEncryptedCollection()` if any
+   error is encountered while creating data keys or creating the collection. The
+   original exception and modified ``encryptedFields`` option can be accessed
+   via the ``getPrevious()`` and ``getEncryptedFields()`` methods, respectively.
+
+   This class extends the library's :phpclass:`RuntimeException
+   ` class.
+
+----
+
 MongoDB\\Exception\\InvalidArgumentException
 --------------------------------------------
 
diff --git a/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt b/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt
new file mode 100644
index 000000000..07dc082c1
--- /dev/null
+++ b/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt
@@ -0,0 +1,144 @@
+==============================================
+MongoDB\\Database::createEncryptedCollection()
+==============================================
+
+.. versionadded:: 1.16
+
+.. default-domain:: mongodb
+
+.. contents:: On this page
+   :local:
+   :backlinks: none
+   :depth: 1
+   :class: singlecol
+
+.. note::
+
+   Queryable Encryption is in public preview and available for evaluation
+   purposes. It is not yet recommended for production deployments as breaking
+   changes may be introduced. See the
+   `Queryable Encryption Preview `_
+   blog post for more information.
+
+Definition
+----------
+
+.. phpmethod:: MongoDB\\Database::createEncryptedCollection()
+
+   Explicitly creates an encrypted collection.
+
+   .. code-block:: php
+
+      function createEncryptedCollection(string $collectionName, MongoDB\Driver\ClientEncryption $clientEncryption, string $kmsProvider, ?array $masterKey, array $options): array
+
+   This method will automatically create data keys for any encrypted fields
+   where ``keyId`` is ``null``. Data keys will be created using
+   :php:`MongoDB\\Driver\\ClientEncryption::createDataKey() `
+   and the provided ``$kmsProvider`` and ``$masterKey`` parameters. A copy of
+   the modified ``encryptedFields`` option will be returned in addition to the
+   result from creating the collection.
+
+   This method does not affect any auto encryption settings on existing
+   :phpclass:`MongoDB\\Client` objects. Users must configure auto encryption
+   after creating the encrypted collection with ``createEncryptedCollection()``.
+
+   This method has the following parameters:
+
+   .. include:: /includes/apiargs/MongoDBDatabase-method-createEncryptedCollection-param.rst
+
+   The ``$options`` parameter supports the same options as
+   :phpmethod:`MongoDB\\Database::createCollection()`. The ``encryptedFields``
+   option is required.
+
+Return Values
+-------------
+
+A tuple (i.e. two-element array) containing the result document from the
+:manual:`create ` command (an array or object
+according to the ``typeMap`` option) and the modified ``encryptedFields``
+option.
+
+Errors/Exceptions
+-----------------
+
+:phpclass:`MongoDB\\Exception\\CreateEncryptedCollectionException` if any error
+is encountered creating data keys or the collection. The original exception and
+modified ``encryptedFields`` option can be accessed via the ``getPrevious()``
+and ``getEncryptedFields()`` methods, respectively.
+
+.. include:: /includes/extracts/error-invalidargumentexception.rst
+
+Example
+-------
+
+The following example creates an encrypted ``users`` collection in the ``test``
+database. The ``ssn`` field within the ``users`` collection will be defined as
+an encrypted string field.
+
+.. code-block:: php
+
+   createClientEncryption([
+       'keyVaultNamespace' => 'keyvault.datakeys',
+       'kmsProviders' => [
+           'local' => ['key' => new MongoDB\BSON\Binary(base64_decode(LOCAL_MASTERKEY), 0)],
+        ],
+   );
+
+   [$result, $encryptedFields] = $client->test->createEncryptedCollection(
+       'users',
+       $clientEncryption,
+       'local',
+       null,
+       [
+           'encryptedFields' => [
+               'fields' => [
+                   ['path' => 'ssn', 'bsonType' => 'string', 'keyId' => null],
+               ],
+           ],
+       ]
+   );
+
+If the encrypted collection was successfully created, ``$result`` will contain
+the response document from the ``create`` command and
+``$encryptedFields['fields'][0]['keyId']`` will contain a
+:php:`MongoDB\\BSON\\Binary ` object with subtype 4
+(i.e. UUID).
+
+The modified ``encryptedFields`` option can then be used to construct a new
+:phpclass:`MongoDB\\Client` with auto encryption enabled.
+
+.. code-block:: php
+
+    [
+               'keyVaultNamespace' => 'keyvault.datakeys',
+               'kmsProviders' => [
+                   'local' => ['key' => new MongoDB\BSON\Binary(base64_decode(LOCAL_MASTERKEY), 0)],
+                ],
+                'encryptedFieldsMap' => [
+                    'test.users' => $encryptedFields,
+                ],
+           ],
+       ]
+   );
+
+See Also
+--------
+
+- :phpmethod:`MongoDB\\Database::createCollection()`
+- :phpmethod:`MongoDB\\Client::createClientEncryption()`
+- :php:`MongoDB\\Driver\\ClientEncryption::createDataKey() `
+- :manual:`create ` command reference in the MongoDB
+  manual
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index a2d56ccce..1422e5682 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -175,6 +175,7 @@
         /src/GridFS/StreamWrapper
         /tests/DocumentationExamplesTest.php
         /tests/GridFS/UnusableStream.php
+        /tests/SpecTests/ClientSideEncryption/Prose*
     
     
         /examples
@@ -183,4 +184,7 @@
     
         /examples
     
+    
+        /tests/SpecTests/ClientSideEncryption/Prose*
+    
 
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 276f9370e..96bc27919 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -491,6 +491,12 @@
       $options['writeConcern']
     
   
+  
+    
+      ! is_array($encryptedFields['fields'])
+      ! is_array($field) && ! is_object($field)
+    
+  
   
     
       is_array($index)
diff --git a/src/Database.php b/src/Database.php
index 9bb2484dd..d461c65ce 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -18,12 +18,14 @@
 namespace MongoDB;
 
 use Iterator;
+use MongoDB\Driver\ClientEncryption;
 use MongoDB\Driver\Cursor;
 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
 use MongoDB\Driver\Manager;
 use MongoDB\Driver\ReadConcern;
 use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\WriteConcern;
+use MongoDB\Exception\CreateEncryptedCollectionException;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Exception\UnexpectedValueException;
 use MongoDB\Exception\UnsupportedException;
@@ -33,7 +35,7 @@
 use MongoDB\Model\CollectionInfoIterator;
 use MongoDB\Operation\Aggregate;
 use MongoDB\Operation\CreateCollection;
-use MongoDB\Operation\CreateIndexes;
+use MongoDB\Operation\CreateEncryptedCollection;
 use MongoDB\Operation\DatabaseCommand;
 use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\DropDatabase;
@@ -42,6 +44,7 @@
 use MongoDB\Operation\ModifyCollection;
 use MongoDB\Operation\RenameCollection;
 use MongoDB\Operation\Watch;
+use Throwable;
 use Traversable;
 
 use function is_array;
@@ -256,7 +259,13 @@ public function command($command, array $options = [])
     /**
      * Create a new collection explicitly.
      *
+     * If the "encryptedFields" option is specified, this method additionally
+     * creates related metadata collections and an index on the encrypted
+     * collection.
+     *
      * @see CreateCollection::__construct() for supported options
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#create-collection-helper
+     * @see https://www.mongodb.com/docs/manual/core/queryable-encryption/fundamentals/manage-collections/
      * @return array|object Command result document
      * @throws UnsupportedException if options are not supported by the selected server
      * @throws InvalidArgumentException for parameter/option parsing errors
@@ -268,36 +277,63 @@ public function createCollection(string $collectionName, array $options = [])
             $options['typeMap'] = $this->typeMap;
         }
 
-        $server = select_server($this->manager, $options);
-
         if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
             $options['writeConcern'] = $this->writeConcern;
         }
 
-        $encryptedFields = $options['encryptedFields']
-            ?? get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager)
-            ?? null;
+        if (! isset($options['encryptedFields'])) {
+            $options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager);
+        }
 
-        if ($encryptedFields !== null) {
-            // encryptedFields is passed to the create command
-            $options['encryptedFields'] = $encryptedFields;
+        $operation = isset($options['encryptedFields'])
+            ? new CreateEncryptedCollection($this->databaseName, $collectionName, $options)
+            : new CreateCollection($this->databaseName, $collectionName, $options);
 
-            $encryptedFields = (array) $encryptedFields;
-            $enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]];
-            (new CreateCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc', $enxcolOptions))->execute($server);
-            (new CreateCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc', $enxcolOptions))->execute($server);
-            (new CreateCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc', $enxcolOptions))->execute($server);
-        }
+        $server = select_server($this->manager, $options);
 
-        $operation = new CreateCollection($this->databaseName, $collectionName, $options);
+        return $operation->execute($server);
+    }
 
-        $result = $operation->execute($server);
+    /**
+     * Create a new encrypted collection explicitly.
+     *
+     * The "encryptedFields" option is required.
+     *
+     * This method will automatically create data keys for any encrypted fields
+     * where "keyId" is null. A copy of the modified "encryptedFields" option
+     * will be returned in addition to the result from creating the collection.
+     *
+     * If any error is encountered creating data keys or the collection, a
+     * CreateEncryptedCollectionException will be thrown. The original exception
+     * and modified "encryptedFields" option can be accessed via the
+     * getPrevious() and getEncryptedFields() methods, respectively.
+     *
+     * @see CreateCollection::__construct() for supported options
+     * @return array A tuple containing the command result document from creating the collection and the modified "encryptedFields" option
+     * @throws InvalidArgumentException for parameter/option parsing errors
+     * @throws CreateEncryptedCollectionException for any errors creating data keys or creating the collection
+     */
+    public function createEncryptedCollection(string $collectionName, ClientEncryption $clientEncryption, string $kmsProvider, ?array $masterKey, array $options): array
+    {
+        if (! isset($options['typeMap'])) {
+            $options['typeMap'] = $this->typeMap;
+        }
 
-        if ($encryptedFields !== null) {
-            (new CreateIndexes($this->databaseName, $collectionName, [['key' => ['__safeContent__' => 1]]]))->execute($server);
+        if (! isset($options['writeConcern']) && ! is_in_transaction($options)) {
+            $options['writeConcern'] = $this->writeConcern;
         }
 
-        return $result;
+        $operation = new CreateEncryptedCollection($this->databaseName, $collectionName, $options);
+        $server = select_server($this->manager, $options);
+
+        try {
+            $operation->createDataKeys($clientEncryption, $kmsProvider, $masterKey, $encryptedFields);
+            $result = $operation->execute($server);
+
+            return [$result, $encryptedFields];
+        } catch (Throwable $e) {
+            throw new CreateEncryptedCollectionException($e, $encryptedFields ?? []);
+        }
     }
 
     /**
diff --git a/src/Exception/CreateEncryptedCollectionException.php b/src/Exception/CreateEncryptedCollectionException.php
new file mode 100644
index 000000000..7330c7f6f
--- /dev/null
+++ b/src/Exception/CreateEncryptedCollectionException.php
@@ -0,0 +1,56 @@
+getMessage()), 0, $previous);
+
+        $this->encryptedFields = $encryptedFields;
+    }
+
+    /**
+     * Returns the encryptedFields option in its last known state before the
+     * operation was interrupted.
+     *
+     * This can be used to infer which data keys were successfully created;
+     * however, it is possible that additional data keys were successfully
+     * created and are not present in the returned value. For example, if the
+     * operation was interrupted by a timeout error when creating a data key,
+     * the write may actually have succeeded on the server but the key will not
+     * be present in the returned value.
+     */
+    public function getEncryptedFields(): array
+    {
+        return $this->encryptedFields;
+    }
+}
diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php
index 8860a2889..12aaa3dbb 100644
--- a/src/Operation/CreateCollection.php
+++ b/src/Operation/CreateCollection.php
@@ -87,7 +87,8 @@ class CreateCollection implements Executable
      *
      *  * collation (document): Collation specification.
      *
-     *  * encryptedFields (document): CSFLE specification.
+     *  * encryptedFields (document): Configuration for encrypted fields.
+     *    See: https://www.mongodb.com/docs/manual/core/queryable-encryption/fundamentals/encrypt-and-query/
      *
      *  * expireAfterSeconds: The TTL for documents in time series collections.
      *
diff --git a/src/Operation/CreateEncryptedCollection.php b/src/Operation/CreateEncryptedCollection.php
new file mode 100644
index 000000000..728c2a161
--- /dev/null
+++ b/src/Operation/CreateEncryptedCollection.php
@@ -0,0 +1,167 @@
+createCollection = new CreateCollection($databaseName, $collectionName, $options);
+
+        /** @psalm-var array{eccCollection?: ?string, ecocCollection?: ?string, escCollection?: ?string} */
+        $encryptedFields = (array) $options['encryptedFields'];
+        $enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]];
+
+        $this->createMetadataCollections = [
+            new CreateCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc', $enxcolOptions),
+            new CreateCollection($databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc', $enxcolOptions),
+            new CreateCollection($databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc', $enxcolOptions),
+        ];
+
+        $this->createSafeContentIndex = new CreateIndexes($databaseName, $collectionName, [['key' => ['__safeContent__' => 1]]]);
+
+        $this->databaseName = $databaseName;
+        $this->collectionName = $collectionName;
+        $this->options = $options;
+    }
+
+    /**
+     * Create data keys for any encrypted fields where "keyId" is null.
+     *
+     * This method should be called before execute(), as it may modify the
+     * "encryptedFields" option and reconstruct the internal CreateCollection
+     * operation used for creating the encrypted collection.
+     *
+     * The $encryptedFields reference parameter may be used to determine which
+     * data keys have been created.
+     *
+     * @see \MongoDB\Database::createEncryptedCollection()
+     * @see https://www.php.net/manual/en/mongodb-driver-clientencryption.createdatakey.php
+     * @throws DriverRuntimeException for errors creating a data key
+     */
+    public function createDataKeys(ClientEncryption $clientEncryption, string $kmsProvider, ?array $masterKey, ?array &$encryptedFields = null): void
+    {
+        /** @psalm-var array{fields: list} */
+        $encryptedFields = (array) $this->options['encryptedFields'];
+
+        /* NOP if there are no fields to examine. If the type is invalid, defer
+         * to the server to raise an error in execute(). */
+        if (! isset($encryptedFields['fields']) || ! is_array($encryptedFields['fields'])) {
+            return;
+        }
+
+        $createDataKeyArgs = [
+            $kmsProvider,
+            $masterKey !== null ? ['masterKey' => $masterKey] : [],
+        ];
+
+        foreach ($encryptedFields['fields'] as $i => $field) {
+            // Skip invalid types and defer to the server to raise an error
+            if (! is_array($field) && ! is_object($field)) {
+                continue;
+            }
+
+            $field = (array) $field;
+
+            if (array_key_exists('keyId', $field) && $field['keyId'] === null) {
+                $field['keyId'] = $clientEncryption->createDataKey(...$createDataKeyArgs);
+                $encryptedFields['fields'][$i] = $field;
+            }
+        }
+
+        $this->options['encryptedFields'] = $encryptedFields;
+        $this->createCollection = new CreateCollection($this->databaseName, $this->collectionName, $this->options);
+    }
+
+    /**
+     * @see Executable::execute()
+     * @return array|object Command result document from creating the encrypted collection
+     * @throws DriverRuntimeException for other driver errors (e.g. connection errors)
+     */
+    public function execute(Server $server)
+    {
+        foreach ($this->createMetadataCollections as $createMetadataCollection) {
+            $createMetadataCollection->execute($server);
+        }
+
+        $result = $this->createCollection->execute($server);
+
+        $this->createSafeContentIndex->execute($server);
+
+        return $result;
+    }
+}
diff --git a/src/functions.php b/src/functions.php
index dd2d94021..412ef7a58 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -129,10 +129,10 @@ function generate_index_name($document): string
  * autoEncryption driver option (if available).
  *
  * @internal
- * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#drop-collection-helper
- * @see Collection::drop
- * @see Database::createCollection
- * @see Database::dropCollection
+ * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#collection-encryptedfields-lookup-getencryptedfields
+ * @see Collection::drop()
+ * @see Database::createCollection()
+ * @see Database::dropCollection()
  * @return array|object|null
  */
 function get_encrypted_fields_from_driver(string $databaseName, string $collectionName, Manager $manager)
@@ -146,9 +146,9 @@ function get_encrypted_fields_from_driver(string $databaseName, string $collecti
  * Return a collection's encryptedFields option from the server (if any).
  *
  * @internal
- * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#drop-collection-helper
- * @see Collection::drop
- * @see Database::dropCollection
+ * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/client-side-encryption.rst#collection-encryptedfields-lookup-getencryptedfields
+ * @see Collection::drop()
+ * @see Database::dropCollection()
  * @return array|object|null
  */
 function get_encrypted_fields_from_server(string $databaseName, string $collectionName, Manager $manager, Server $server)
@@ -454,8 +454,8 @@ function create_field_path_type_map(array $typeMap, string $fieldPath): array
  * from the initial call have elapsed. After that, no retries will happen and
  * the helper will throw the last exception received from the driver.
  *
- * @see Client::startSession
- * @see Session::startTransaction for supported transaction options
+ * @see Client::startSession()
+ * @see Session::startTransaction() for supported transaction options
  *
  * @param Session  $session            A session object as retrieved by Client::startSession
  * @param callable $callback           A callback that will be invoked within the transaction
diff --git a/tests/Exception/CreateEncryptedCollectionExceptionTest.php b/tests/Exception/CreateEncryptedCollectionExceptionTest.php
new file mode 100644
index 000000000..b48273493
--- /dev/null
+++ b/tests/Exception/CreateEncryptedCollectionExceptionTest.php
@@ -0,0 +1,26 @@
+ []];
+
+        $e = new CreateEncryptedCollectionException(new Exception(), $encryptedFields);
+        $this->assertSame($encryptedFields, $e->getEncryptedFields());
+    }
+
+    public function testGetPrevious(): void
+    {
+        $previous = new Exception();
+
+        $e = new CreateEncryptedCollectionException($previous, ['fields' => []]);
+        $this->assertSame($previous, $e->getPrevious());
+    }
+}
diff --git a/tests/Operation/CreateEncryptedCollectionFunctionalTest.php b/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
new file mode 100644
index 000000000..cdf9ac31d
--- /dev/null
+++ b/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
@@ -0,0 +1,174 @@
+skipIfClientSideEncryptionIsNotSupported();
+
+        if (! static::isCryptSharedLibAvailable() && ! static::isMongocryptdAvailable()) {
+            $this->markTestSkipped('Neither crypt_shared nor mongocryptd are available');
+        }
+
+        if ($this->isStandalone() || ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets())) {
+            $this->markTestSkipped('Queryable Encryption requires replica sets');
+        }
+
+        if (version_compare($this->getServerVersion(), '6.0.0', '<')) {
+            $this->markTestSkipped('Queryable Encryption requires MongoDB 6.0 or later');
+        }
+
+        $client = static::createTestClient();
+
+        /* Since test cases may create encrypted collections, ensure that the
+         * collection and any "enxcol_" collections do not exist. Specify
+         * "encryptedFields" to ensure "enxcol_" collections are handled. */
+        $client->selectCollection($this->getDatabaseName(), $this->getCollectionName())->drop(['encryptedFields' => []]);
+
+        // Drop the key vault with a majority write concern
+        $client->selectCollection('keyvault', 'datakeys')->drop(['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
+
+        $this->clientEncryption = $client->createClientEncryption([
+            'keyVaultNamespace' => 'keyvault.datakeys',
+            'kmsProviders' => [
+                'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)],
+            ],
+        ]);
+    }
+
+    public function testCreateDataKeysNopIfFieldsArrayIsMissing(): void
+    {
+        $operation = new CreateEncryptedCollection(
+            $this->getDatabaseName(),
+            $this->getCollectionName(),
+            ['encryptedFields' => []]
+        );
+
+        $operation->createDataKeys(
+            $this->clientEncryption,
+            'local',
+            null,
+            $encryptedFields
+        );
+
+        $this->assertSame([], $encryptedFields);
+    }
+
+    public function testCreateDataKeysNopIfFieldsArrayIsInvalid(): void
+    {
+        $operation = new CreateEncryptedCollection(
+            $this->getDatabaseName(),
+            $this->getCollectionName(),
+            ['encryptedFields' => ['fields' => 'not-an-array']]
+        );
+
+        $operation->createDataKeys(
+            $this->clientEncryption,
+            'local',
+            null,
+            $encryptedFields
+        );
+
+        $this->assertSame(['fields' => 'not-an-array'], $encryptedFields);
+    }
+
+    public function testCreateDataKeysSkipsNonDocumentFields(): void
+    {
+        $operation = new CreateEncryptedCollection(
+            $this->getDatabaseName(),
+            $this->getCollectionName(),
+            ['encryptedFields' => ['fields' => ['not-an-array-or-object']]]
+        );
+
+        $operation->createDataKeys(
+            $this->clientEncryption,
+            'local',
+            null,
+            $encryptedFields
+        );
+
+        $this->assertSame(['fields' => ['not-an-array-or-object']], $encryptedFields);
+    }
+
+    public function testCreateDataKeysDoesNotModifyEncryptedFieldsObjectOption(): void
+    {
+        $originalField = (object) ['path' => 'ssn', 'bsonType' => 'string', 'keyId' => null];
+        $originalEncryptedFields = (object) ['fields' => [$originalField]];
+
+        $operation = new CreateEncryptedCollection(
+            $this->getDatabaseName(),
+            $this->getCollectionName(),
+            ['encryptedFields' => $originalEncryptedFields]
+        );
+
+        $operation->createDataKeys(
+            $this->clientEncryption,
+            'local',
+            null,
+            $modifiedEncryptedFields
+        );
+
+        $this->assertSame($originalField, $originalEncryptedFields->fields[0]);
+        $this->assertNull($originalField->keyId);
+
+        $this->assertInstanceOf(Binary::class, $modifiedEncryptedFields['fields'][0]['keyId'] ?? null);
+    }
+
+    public static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client
+    {
+        if (isset($driverOptions['autoEncryption']) && getenv('CRYPT_SHARED_LIB_PATH')) {
+            $driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'] = getenv('CRYPT_SHARED_LIB_PATH');
+        }
+
+        return parent::createTestClient($uri, $options, $driverOptions);
+    }
+
+    private static function isCryptSharedLibAvailable(): bool
+    {
+        $cryptSharedLibPath = getenv('CRYPT_SHARED_LIB_PATH');
+
+        if ($cryptSharedLibPath === false) {
+            return false;
+        }
+
+        return is_readable($cryptSharedLibPath);
+    }
+
+    private static function isMongocryptdAvailable(): bool
+    {
+        $paths = explode(PATH_SEPARATOR, getenv("PATH"));
+
+        foreach ($paths as $path) {
+            if (is_executable($path . DIRECTORY_SEPARATOR . 'mongocryptd')) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/tests/Operation/CreateEncryptedCollectionTest.php b/tests/Operation/CreateEncryptedCollectionTest.php
new file mode 100644
index 000000000..86b5b03af
--- /dev/null
+++ b/tests/Operation/CreateEncryptedCollectionTest.php
@@ -0,0 +1,34 @@
+expectException(InvalidArgumentException::class);
+        new CreateEncryptedCollection($this->getDatabaseName(), $this->getCollectionName(), $options);
+    }
+
+    public function provideInvalidConstructorOptions(): Generator
+    {
+        yield 'encryptedFields is required' => [
+            [],
+        ];
+
+        foreach ($this->getInvalidDocumentValues() as $value) {
+            yield 'encryptedFields type: ' . get_debug_type($value) => [
+                ['encryptedFields' => $value],
+            ];
+        }
+    }
+}
diff --git a/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php b/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
new file mode 100644
index 000000000..68285f724
--- /dev/null
+++ b/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
@@ -0,0 +1,130 @@
+skipIfClientSideEncryptionIsNotSupported();
+
+        if (! static::isCryptSharedLibAvailable() && ! static::isMongocryptdAvailable()) {
+            $this->markTestSkipped('Neither crypt_shared nor mongocryptd are available');
+        }
+    }
+
+    public static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client
+    {
+        if (isset($driverOptions['autoEncryption']) && getenv('CRYPT_SHARED_LIB_PATH')) {
+            $driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'] = getenv('CRYPT_SHARED_LIB_PATH');
+        }
+
+        return parent::createTestClient($uri, $options, $driverOptions);
+    }
+
+    protected static function getAWSCredentials(): array
+    {
+        return [
+            'accessKeyId' => static::getEnv('AWS_ACCESS_KEY_ID'),
+            'secretAccessKey' => static::getEnv('AWS_SECRET_ACCESS_KEY'),
+        ];
+    }
+
+    protected static function insertKeyVaultData(Client $client, ?array $keyVaultData = null): void
+    {
+        $collection = $client->selectCollection('keyvault', 'datakeys', ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
+        $collection->drop();
+
+        if (empty($keyVaultData)) {
+            return;
+        }
+
+        $collection->insertMany($keyVaultData);
+    }
+
+    private function createInt64(string $value): Int64
+    {
+        $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value);
+        $int64 = sprintf('C:%d:"%s":%d:{%s}', strlen(Int64::class), Int64::class, strlen($array), $array);
+
+        return unserialize($int64);
+    }
+
+    private function createTestCollection(?stdClass $encryptedFields = null, ?stdClass $jsonSchema = null): void
+    {
+        $context = $this->getContext();
+        $options = $context->defaultWriteOptions;
+
+        if (! empty($encryptedFields)) {
+            $options['encryptedFields'] = $encryptedFields;
+        }
+
+        if (! empty($jsonSchema)) {
+            $options['validator'] = ['$jsonSchema' => $jsonSchema];
+        }
+
+        $context->getDatabase()->createCollection($context->collectionName, $options);
+    }
+
+    private static function getEnv(string $name): string
+    {
+        $value = getenv($name);
+
+        if ($value === false) {
+            Assert::markTestSkipped(sprintf('Environment variable "%s" is not defined', $name));
+        }
+
+        return $value;
+    }
+
+    private static function isCryptSharedLibAvailable(): bool
+    {
+        $cryptSharedLibPath = getenv('CRYPT_SHARED_LIB_PATH');
+
+        if ($cryptSharedLibPath === false) {
+            return false;
+        }
+
+        return is_readable($cryptSharedLibPath);
+    }
+
+    private static function isMongocryptdAvailable(): bool
+    {
+        $paths = explode(PATH_SEPARATOR, getenv("PATH"));
+
+        foreach ($paths as $path) {
+            if (is_executable($path . DIRECTORY_SEPARATOR . 'mongocryptd')) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php b/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
new file mode 100644
index 000000000..45e70f248
--- /dev/null
+++ b/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
@@ -0,0 +1,171 @@
+isStandalone() || ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets())) {
+            $this->markTestSkipped('Automatic data encryption key tests require replica sets');
+        }
+
+        if (version_compare($this->getServerVersion(), '6.0.0', '<')) {
+            $this->markTestSkipped('Automatic data encryption key tests require MongoDB 6.0 or later');
+        }
+
+        $client = static::createTestClient();
+        $this->database = $client->selectDatabase($this->getDatabaseName());
+
+        /* Since test cases may create encrypted collections, ensure that the
+         * collection and any "enxcol_" collections do not exist. Specify
+         * "encryptedFields" to ensure "enxcol_" collections are handled. */
+        $this->database->dropCollection($this->getCollectionName(), ['encryptedFields' => []]);
+
+        // Ensure that the key vault is dropped with a majority write concern
+        self::insertKeyVaultData($client, []);
+
+        $this->clientEncryption = $client->createClientEncryption([
+            'keyVaultNamespace' => 'keyvault.datakeys',
+            'kmsProviders' => [
+                'aws' => self::getAWSCredentials(),
+                'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)],
+            ],
+        ]);
+    }
+
+    public function tearDown(): void
+    {
+        $this->clientEncryption = null;
+        $this->database = null;
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/bc37892f360cab9df4082922384e0f4d4233f6d3/source/client-side-encryption/tests/README.rst#case-1-simple-creation-and-validation
+     * @dataProvider provideKmsProviderAndMasterKey
+     */
+    public function testCase1_SimpleCreationAndValidation(string $kmsProvider, ?array $masterKey): void
+    {
+        [$result, $encryptedFields] = $this->database->createEncryptedCollection(
+            $this->getCollectionName(),
+            $this->clientEncryption,
+            $kmsProvider,
+            $masterKey,
+            ['encryptedFields' => ['fields' => [['path' => 'ssn', 'bsonType' => 'string', 'keyId' => null]]]]
+        );
+
+        $this->assertCommandSucceeded($result);
+        $this->assertInstanceOf(Binary::class, $encryptedFields['fields'][0]['keyId'] ?? null);
+
+        $this->expectException(BulkWriteException::class);
+        $this->expectExceptionMessage('Document failed validation');
+        $this->database->selectCollection($this->getCollectionName())->insertOne(['ssn' => '123-45-6789']);
+    }
+
+    public static function provideKmsProviderAndMasterKey(): Generator
+    {
+        yield [
+            'aws',
+            ['region' => 'us-east-1', 'key' => 'arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0'],
+        ];
+
+        yield [
+            'local',
+            null,
+        ];
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/bc37892f360cab9df4082922384e0f4d4233f6d3/source/client-side-encryption/tests/README.rst#case-2-missing-encryptedfields
+     * @dataProvider provideKmsProviderAndMasterKey
+     */
+    public function testCase2_MissingEncryptedFields(string $kmsProvider, ?array $masterKey): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('"encryptedFields" option');
+        $this->database->createEncryptedCollection(
+            $this->getCollectionName(),
+            $this->clientEncryption,
+            $kmsProvider,
+            $masterKey,
+            []
+        );
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/bc37892f360cab9df4082922384e0f4d4233f6d3/source/client-side-encryption/tests/README.rst#case-3-invalid-keyid
+     * @dataProvider provideKmsProviderAndMasterKey
+     */
+    public function testCase3_InvalidKeyId(string $kmsProvider, ?array $masterKey): void
+    {
+        try {
+            $this->database->createEncryptedCollection(
+                $this->getCollectionName(),
+                $this->clientEncryption,
+                $kmsProvider,
+                $masterKey,
+                ['encryptedFields' => ['fields' => [['path' => 'ssn', 'bsonType' => 'string', 'keyId' => false]]]]
+            );
+            $this->fail('CreateEncryptedCollectionException was not thrown');
+        } catch (CreateEncryptedCollectionException $e) {
+            $this->assertFalse($e->getEncryptedFields()['fields'][0]['keyId'], 'Invalid keyId should not be modified');
+
+            $previous = $e->getPrevious();
+            $this->assertInstanceOf(CommandException::class, $previous);
+            $this->assertSame(self::SERVER_ERROR_TYPEMISMATCH, $previous->getCode());
+            $this->assertStringContainsString('keyId', $previous->getMessage());
+        }
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/bc37892f360cab9df4082922384e0f4d4233f6d3/source/client-side-encryption/tests/README.rst#case-4-insert-encrypted-value
+     * @dataProvider provideKmsProviderAndMasterKey
+     */
+    public function testCase4_InsertEncryptedValue(string $kmsProvider, ?array $masterKey): void
+    {
+        [$result, $encryptedFields] = $this->database->createEncryptedCollection(
+            $this->getCollectionName(),
+            $this->clientEncryption,
+            $kmsProvider,
+            $masterKey,
+            ['encryptedFields' => ['fields' => [['path' => 'ssn', 'bsonType' => 'string', 'keyId' => null]]]]
+        );
+
+        $this->assertCommandSucceeded($result);
+        $this->assertInstanceOf(Binary::class, $encryptedFields['fields'][0]['keyId'] ?? null);
+
+        $encrypted = $this->clientEncryption->encrypt('123-45-6789', [
+            'keyId' => $encryptedFields['fields'][0]['keyId'],
+            'algorithm' => ClientEncryption::ALGORITHM_UNINDEXED,
+        ]);
+
+        $collection = $this->database->selectCollection($this->getCollectionName());
+        $insertedId = $collection->insertOne(['ssn' => $encrypted])->getInsertedId();
+        $this->assertNotNull($collection->findOne(['_id' => $insertedId]));
+    }
+}

From 55c62d3e04164dccb25a4558f2ba0608028f22a4 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Wed, 12 Apr 2023 13:45:52 +0800
Subject: [PATCH 273/321] Extract DropEncryptedCollection operation from helper
 methods (#1055)

This is based on the extraction of CreateEncryptedCollection for PHPLIB-913.

Co-authored-by: Andreas Braun 
---
 src/Collection.php                            |  21 ++--
 src/Database.php                              |  21 ++--
 src/Operation/DropEncryptedCollection.php     | 104 ++++++++++++++++++
 .../Operation/DropEncryptedCollectionTest.php |  34 ++++++
 4 files changed, 152 insertions(+), 28 deletions(-)
 create mode 100644 src/Operation/DropEncryptedCollection.php
 create mode 100644 tests/Operation/DropEncryptedCollectionTest.php

diff --git a/src/Collection.php b/src/Collection.php
index 517cd307a..f3d7e38ee 100644
--- a/src/Collection.php
+++ b/src/Collection.php
@@ -40,6 +40,7 @@
 use MongoDB\Operation\DeleteOne;
 use MongoDB\Operation\Distinct;
 use MongoDB\Operation\DropCollection;
+use MongoDB\Operation\DropEncryptedCollection;
 use MongoDB\Operation\DropIndexes;
 use MongoDB\Operation\EstimatedDocumentCount;
 use MongoDB\Operation\Explain;
@@ -495,22 +496,14 @@ public function drop(array $options = [])
             $options['writeConcern'] = $this->writeConcern;
         }
 
-        $encryptedFields = $options['encryptedFields']
-            ?? get_encrypted_fields_from_driver($this->databaseName, $this->collectionName, $this->manager)
-            ?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $this->manager, $server)
-            ?? null;
-
-        if ($encryptedFields !== null) {
-            // encryptedFields is not passed to the drop command
-            unset($options['encryptedFields']);
-
-            $encryptedFields = (array) $encryptedFields;
-            (new DropCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $this->collectionName . '.esc'))->execute($server);
-            (new DropCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecc'))->execute($server);
-            (new DropCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecoc'))->execute($server);
+        if (! isset($options['encryptedFields'])) {
+            $options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $this->collectionName, $this->manager)
+                ?? get_encrypted_fields_from_server($this->databaseName, $this->collectionName, $this->manager, $server);
         }
 
-        $operation = new DropCollection($this->databaseName, $this->collectionName, $options);
+        $operation = isset($options['encryptedFields'])
+            ? new DropEncryptedCollection($this->databaseName, $this->collectionName, $options)
+            : new DropCollection($this->databaseName, $this->collectionName, $options);
 
         return $operation->execute($server);
     }
diff --git a/src/Database.php b/src/Database.php
index d461c65ce..a8338b304 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -39,6 +39,7 @@
 use MongoDB\Operation\DatabaseCommand;
 use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\DropDatabase;
+use MongoDB\Operation\DropEncryptedCollection;
 use MongoDB\Operation\ListCollectionNames;
 use MongoDB\Operation\ListCollections;
 use MongoDB\Operation\ModifyCollection;
@@ -386,22 +387,14 @@ public function dropCollection(string $collectionName, array $options = [])
             $options['writeConcern'] = $this->writeConcern;
         }
 
-        $encryptedFields = $options['encryptedFields']
-            ?? get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager)
-            ?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $this->manager, $server)
-            ?? null;
-
-        if ($encryptedFields !== null) {
-            // encryptedFields is not passed to the drop command
-            unset($options['encryptedFields']);
-
-            $encryptedFields = (array) $encryptedFields;
-            (new DropCollection($this->databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'))->execute($server);
-            (new DropCollection($this->databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'))->execute($server);
-            (new DropCollection($this->databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'))->execute($server);
+        if (! isset($options['encryptedFields'])) {
+            $options['encryptedFields'] = get_encrypted_fields_from_driver($this->databaseName, $collectionName, $this->manager)
+                ?? get_encrypted_fields_from_server($this->databaseName, $collectionName, $this->manager, $server);
         }
 
-        $operation = new DropCollection($this->databaseName, $collectionName, $options);
+        $operation = isset($options['encryptedFields'])
+            ? new DropEncryptedCollection($this->databaseName, $collectionName, $options)
+            : new DropCollection($this->databaseName, $collectionName, $options);
 
         return $operation->execute($server);
     }
diff --git a/src/Operation/DropEncryptedCollection.php b/src/Operation/DropEncryptedCollection.php
new file mode 100644
index 000000000..f6a04dbf8
--- /dev/null
+++ b/src/Operation/DropEncryptedCollection.php
@@ -0,0 +1,104 @@
+dropMetadataCollections = [
+            new DropCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'),
+            new DropCollection($databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'),
+            new DropCollection($databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'),
+        ];
+
+        // DropCollection does not use the "encryptedFields" option
+        unset($options['encryptedFields']);
+
+        $this->dropCollection = new DropCollection($databaseName, $collectionName, $options);
+    }
+
+    /**
+     * @see Executable::execute()
+     * @return array|object Command result document from dropping the encrypted collection
+     * @throws DriverRuntimeException for other driver errors (e.g. connection errors)
+     */
+    public function execute(Server $server)
+    {
+        foreach ($this->dropMetadataCollections as $dropMetadataCollection) {
+            $dropMetadataCollection->execute($server);
+        }
+
+        return $this->dropCollection->execute($server);
+    }
+}
diff --git a/tests/Operation/DropEncryptedCollectionTest.php b/tests/Operation/DropEncryptedCollectionTest.php
new file mode 100644
index 000000000..494f84daf
--- /dev/null
+++ b/tests/Operation/DropEncryptedCollectionTest.php
@@ -0,0 +1,34 @@
+expectException(InvalidArgumentException::class);
+        new DropEncryptedCollection($this->getDatabaseName(), $this->getCollectionName(), $options);
+    }
+
+    public function provideInvalidConstructorOptions(): Generator
+    {
+        yield 'encryptedFields is required' => [
+            [],
+        ];
+
+        foreach ($this->getInvalidDocumentValues() as $value) {
+            yield 'encryptedFields type: ' . get_debug_type($value) => [
+                ['encryptedFields' => $value],
+            ];
+        }
+    }
+}

From 41b0bc8e4b2f6b62f69836adcc66d3cd51d126ac Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Thu, 13 Apr 2023 00:17:25 +0800
Subject: [PATCH 274/321] PHPLIB-1106: Upgrade doctrine/coding-standard to
 11.1.0 (#1058)

* PHPLIB-1106: Upgrade doctrine/coding-standard to ^11.1

Also bumps phpcs to ^3.7

* Specify minimum supported PHP version for CS config

This ensures consistent reporting regardless of the PHP version used to execute phpcs. It also allows removing excludes for sniffs that apply to newer syntax.

* phpcbf: fix SlevomatCodingStandard.Classes.ParentCallSpacing

PHPCBF RESULT SUMMARY
----------------------------------------------------------------------
FILE                                                  FIXED  REMAINING
----------------------------------------------------------------------
src/Model/ChangeStreamIterator.php                    2      0
----------------------------------------------------------------------
A TOTAL OF 2 ERRORS WERE FIXED IN 1 FILE
----------------------------------------------------------------------

Time: 7.86 secs; Memory: 10MB

* phpcbf: fix SlevomatCodingStandard.Commenting.RequireOneLineDocComment

PHPCBF RESULT SUMMARY
-------------------------------------------------------------------------
FILE                                                     FIXED  REMAINING
-------------------------------------------------------------------------
tests/Operation/DropCollectionTest.php                   1      0
tests/Operation/ListIndexesTest.php                      1      0
tests/Operation/EstimatedDocumentCountTest.php           1      0
tests/Operation/RenameCollectionTest.php                 1      0
tests/Command/ListDatabasesTest.php                      1      0
tests/Operation/ModifyCollectionTest.php                 1      0
tests/Operation/ExplainTest.php                          1      0
tests/Operation/InsertOneTest.php                        2      0
tests/Operation/UpdateManyTest.php                       3      0
tests/Operation/CountTest.php                            2      0
tests/Operation/UpdateOneTest.php                        3      0
tests/Operation/CreateIndexesTest.php                    2      0
tests/UnifiedSpecTests/FailPointObserver.php             3      0
tests/Operation/DeleteTest.php                           4      0
tests/Operation/ReplaceOneTest.php                       3      0
src/Model/CallbackIterator.php                           3      0
tests/Command/ListCollectionsTest.php                    1      0
src/InsertOneResult.php                                  1      0
tests/PedantryTest.php                                   1      0
tests/Operation/DropIndexesTest.php                      1      0
tests/Operation/WatchTest.php                            1      0
tests/GridFS/WritableStreamFunctionalTest.php            3      0
src/Model/DatabaseInfo.php                               1      0
tests/Operation/UpdateTest.php                           3      0
tests/Operation/FindOneFunctionalTest.php                1      0
tests/Operation/InsertManyTest.php                       2      0
tests/Operation/DropEncryptedCollectionTest.php          1      0
tests/Operation/CreateEncryptedCollectionTest.php        1      0
tests/Operation/FindOneAndUpdateTest.php                 4      0
tests/Operation/FindAndModifyTest.php                    1      0
src/Model/CachingIterator.php                            4      0
tests/Model/IndexInputTest.php                           2      0
tests/Operation/FindOneAndReplaceTest.php                4      0
tests/Operation/DropDatabaseTest.php                     1      0
src/ChangeStream.php                                     1      0
tests/Operation/InsertOneFunctionalTest.php              3      0
tests/Operation/InsertManyFunctionalTest.php             2      0
src/Operation/WithTransaction.php                        1      0
tests/Model/BSONIteratorTest.php                         1      0
tests/Operation/DistinctTest.php                         2      0
tests/Operation/AggregateTest.php                        1      0
tests/Operation/DropDatabaseFunctionalTest.php           1      0
src/Model/ChangeStreamIterator.php                       3      0
tests/UnifiedSpecTests/EventCollector.php                3      0
src/Model/IndexInfo.php                                  1      0
tests/SpecTests/ReadWriteConcernSpecTest.php             1      0
tests/Operation/DropCollectionFunctionalTest.php         1      0
src/Model/BSONIterator.php                               1      0
tests/Operation/CreateCollectionTest.php                 1      0
tests/UnifiedSpecTests/EntityMap.php                     3      0
tests/Model/ChangeStreamIteratorTest.php                 3      0
tests/Operation/FindAndModifyFunctionalTest.php          2      0
tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php     2      0
tests/Operation/DeleteFunctionalTest.php                 1      0
tests/GridFS/BucketFunctionalTest.php                    15     0
tests/FunctionsTest.php                                  9      0
tests/Exception/InvalidArgumentExceptionTest.php         1      0
tests/Operation/FindTest.php                             3      0
tests/Operation/UpdateFunctionalTest.php                 4      0
tests/UnifiedSpecTests/UnifiedSpecTest.php               10     0
src/Model/CollectionInfo.php                             1      0
tests/Operation/DatabaseCommandTest.php                  2      0
tests/SpecTests/DocumentsMatchConstraintTest.php         2      0
tests/SpecTests/TransactionsSpecTest.php                 1      0
tests/Operation/BulkWriteTest.php                        20     0
tests/GridFS/ReadableStreamFunctionalTest.php            6      0
tests/Database/DatabaseFunctionalTest.php                3      0
tests/Operation/AggregateFunctionalTest.php              1      0
src/GridFS/WritableStream.php                            1      0
tests/Operation/MapReduceFunctionalTest.php              2      0
tests/Operation/DistinctFunctionalTest.php               1      0
tests/UnifiedSpecTests/EventObserver.php                 3      0
tests/Collection/CrudSpecFunctionalTest.php              1      0
tests/Operation/FindFunctionalTest.php                   1      0
tests/Operation/FindOneAndDeleteTest.php                 2      0
src/Operation/MapReduce.php                              1      0
tests/Operation/CountDocumentsTest.php                   2      0
tests/Operation/ExplainFunctionalTest.php                15     0
tests/Operation/MapReduceTest.php                        2      0
tests/SpecTests/ErrorExpectation.php                     2      0
tests/UnifiedSpecTests/Constraint/MatchesTest.php        2      0
tests/SpecTests/Operation.php                            4      0
tests/Operation/BulkWriteFunctionalTest.php              6      0
tests/SpecTests/PrimaryStepDownSpecTest.php              6      0
tests/ClientTest.php                                     2      0
tests/Collection/CollectionFunctionalTest.php            8      0
tests/DocumentationExamplesTest.php                      3      0
tests/Operation/WatchFunctionalTest.php                  1      0
-------------------------------------------------------------------------
A TOTAL OF 242 ERRORS WERE FIXED IN 88 FILES
-------------------------------------------------------------------------

Time: 13.38 secs; Memory: 10MB
---
 composer.json                                 |  4 +-
 phpcs.xml.dist                                | 14 +---
 src/ChangeStream.php                          |  4 +-
 src/GridFS/WritableStream.php                 |  4 +-
 src/InsertOneResult.php                       |  4 +-
 src/Model/BSONIterator.php                    |  4 +-
 src/Model/CachingIterator.php                 | 16 +---
 src/Model/CallbackIterator.php                | 12 +--
 src/Model/ChangeStreamIterator.php            | 14 ++--
 src/Model/CollectionInfo.php                  |  4 +-
 src/Model/DatabaseInfo.php                    |  4 +-
 src/Model/IndexInfo.php                       |  4 +-
 src/Operation/MapReduce.php                   |  4 +-
 src/Operation/WithTransaction.php             |  4 +-
 tests/ClientTest.php                          |  8 +-
 tests/Collection/CollectionFunctionalTest.php | 32 ++------
 tests/Collection/CrudSpecFunctionalTest.php   |  4 +-
 tests/Command/ListCollectionsTest.php         |  4 +-
 tests/Command/ListDatabasesTest.php           |  4 +-
 tests/Database/DatabaseFunctionalTest.php     | 12 +--
 tests/DocumentationExamplesTest.php           | 12 +--
 .../InvalidArgumentExceptionTest.php          |  4 +-
 tests/FunctionsTest.php                       | 36 +++------
 tests/GridFS/BucketFunctionalTest.php         | 60 ++++----------
 tests/GridFS/ReadableStreamFunctionalTest.php | 24 ++----
 tests/GridFS/WritableStreamFunctionalTest.php | 12 +--
 tests/Model/BSONIteratorTest.php              |  4 +-
 tests/Model/ChangeStreamIteratorTest.php      | 12 +--
 tests/Model/IndexInputTest.php                |  8 +-
 tests/Operation/AggregateFunctionalTest.php   |  4 +-
 tests/Operation/AggregateTest.php             |  4 +-
 tests/Operation/BulkWriteFunctionalTest.php   | 24 ++----
 tests/Operation/BulkWriteTest.php             | 80 +++++--------------
 tests/Operation/CountDocumentsTest.php        |  8 +-
 tests/Operation/CountTest.php                 |  8 +-
 tests/Operation/CreateCollectionTest.php      |  4 +-
 .../CreateEncryptedCollectionTest.php         |  4 +-
 tests/Operation/CreateIndexesTest.php         |  8 +-
 tests/Operation/DatabaseCommandTest.php       |  8 +-
 tests/Operation/DeleteFunctionalTest.php      |  4 +-
 tests/Operation/DeleteTest.php                | 16 +---
 tests/Operation/DistinctFunctionalTest.php    |  4 +-
 tests/Operation/DistinctTest.php              |  8 +-
 .../DropCollectionFunctionalTest.php          |  4 +-
 tests/Operation/DropCollectionTest.php        |  4 +-
 .../Operation/DropDatabaseFunctionalTest.php  |  4 +-
 tests/Operation/DropDatabaseTest.php          |  4 +-
 .../Operation/DropEncryptedCollectionTest.php |  4 +-
 tests/Operation/DropIndexesTest.php           |  4 +-
 .../Operation/EstimatedDocumentCountTest.php  |  4 +-
 tests/Operation/ExplainFunctionalTest.php     | 60 ++++----------
 tests/Operation/ExplainTest.php               |  4 +-
 .../Operation/FindAndModifyFunctionalTest.php |  8 +-
 tests/Operation/FindAndModifyTest.php         |  4 +-
 tests/Operation/FindFunctionalTest.php        |  4 +-
 tests/Operation/FindOneAndDeleteTest.php      |  8 +-
 tests/Operation/FindOneAndReplaceTest.php     | 16 +---
 tests/Operation/FindOneAndUpdateTest.php      | 16 +---
 tests/Operation/FindOneFunctionalTest.php     |  4 +-
 tests/Operation/FindTest.php                  | 12 +--
 tests/Operation/InsertManyFunctionalTest.php  |  8 +-
 tests/Operation/InsertManyTest.php            |  8 +-
 tests/Operation/InsertOneFunctionalTest.php   | 12 +--
 tests/Operation/InsertOneTest.php             |  8 +-
 tests/Operation/ListIndexesTest.php           |  4 +-
 tests/Operation/MapReduceFunctionalTest.php   |  8 +-
 tests/Operation/MapReduceTest.php             |  8 +-
 tests/Operation/ModifyCollectionTest.php      |  4 +-
 tests/Operation/RenameCollectionTest.php      |  4 +-
 tests/Operation/ReplaceOneTest.php            | 12 +--
 tests/Operation/UpdateFunctionalTest.php      | 16 +---
 tests/Operation/UpdateManyTest.php            | 12 +--
 tests/Operation/UpdateOneTest.php             | 12 +--
 tests/Operation/UpdateTest.php                | 12 +--
 tests/Operation/WatchFunctionalTest.php       |  4 +-
 tests/Operation/WatchTest.php                 |  4 +-
 tests/PedantryTest.php                        |  4 +-
 .../DocumentsMatchConstraintTest.php          |  8 +-
 tests/SpecTests/ErrorExpectation.php          |  8 +-
 tests/SpecTests/Operation.php                 | 16 +---
 tests/SpecTests/PrimaryStepDownSpecTest.php   | 24 ++----
 tests/SpecTests/ReadWriteConcernSpecTest.php  |  4 +-
 tests/SpecTests/TransactionsSpecTest.php      |  4 +-
 .../Constraint/IsBsonTypeTest.php             |  8 +-
 .../Constraint/MatchesTest.php                |  8 +-
 tests/UnifiedSpecTests/EntityMap.php          | 12 +--
 tests/UnifiedSpecTests/EventCollector.php     | 12 +--
 tests/UnifiedSpecTests/EventObserver.php      | 12 +--
 tests/UnifiedSpecTests/FailPointObserver.php  | 12 +--
 tests/UnifiedSpecTests/UnifiedSpecTest.php    | 40 +++-------
 90 files changed, 249 insertions(+), 739 deletions(-)

diff --git a/composer.json b/composer.json
index 1ddd6783d..7540bd0da 100644
--- a/composer.json
+++ b/composer.json
@@ -17,8 +17,8 @@
         "symfony/polyfill-php80": "^1.19"
     },
     "require-dev": {
-        "squizlabs/php_codesniffer": "^3.6",
-        "doctrine/coding-standard": "^9.0",
+        "squizlabs/php_codesniffer": "^3.7",
+        "doctrine/coding-standard": "^11.1",
         "symfony/phpunit-bridge": "^5.2",
         "vimeo/psalm": "^4.28"
     },
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 1422e5682..02b0fd035 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -14,21 +14,13 @@
     tests
     tools
 
+    
+    
+
     
     
     
     
-        
-        
-        
-
-        
-        
-
-        
-        
-
-
         
         
         
diff --git a/src/ChangeStream.php b/src/ChangeStream.php
index 33c461801..e824b87d9 100644
--- a/src/ChangeStream.php
+++ b/src/ChangeStream.php
@@ -112,9 +112,7 @@ public function current()
         return $this->iterator->current();
     }
 
-    /**
-     * @return CursorId
-     */
+    /** @return CursorId */
     public function getCursorId()
     {
         return $this->iterator->getInnerIterator()->getId();
diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php
index 43519e09b..73f5b44cc 100644
--- a/src/GridFS/WritableStream.php
+++ b/src/GridFS/WritableStream.php
@@ -255,9 +255,7 @@ private function abort(): void
         $this->isClosed = true;
     }
 
-    /**
-     * @return mixed
-     */
+    /** @return mixed */
     private function fileCollectionInsert()
     {
         $this->file['length'] = $this->length;
diff --git a/src/InsertOneResult.php b/src/InsertOneResult.php
index 80eb9cf22..0a387579f 100644
--- a/src/InsertOneResult.php
+++ b/src/InsertOneResult.php
@@ -34,9 +34,7 @@ class InsertOneResult
     /** @var boolean */
     private $isAcknowledged;
 
-    /**
-     * @param mixed $insertedId
-     */
+    /** @param mixed $insertedId */
     public function __construct(WriteResult $writeResult, $insertedId)
     {
         $this->writeResult = $writeResult;
diff --git a/src/Model/BSONIterator.php b/src/Model/BSONIterator.php
index 2bddc264c..25d9b613d 100644
--- a/src/Model/BSONIterator.php
+++ b/src/Model/BSONIterator.php
@@ -128,9 +128,7 @@ public function rewind()
         $this->advance();
     }
 
-    /**
-     * @see https://php.net/iterator.valid
-     */
+    /** @see https://php.net/iterator.valid */
     #[ReturnTypeWillChange]
     public function valid(): bool
     {
diff --git a/src/Model/CachingIterator.php b/src/Model/CachingIterator.php
index f2a7dd25b..d1ad098d4 100644
--- a/src/Model/CachingIterator.php
+++ b/src/Model/CachingIterator.php
@@ -70,9 +70,7 @@ public function __construct(Traversable $traversable)
         $this->storeCurrentItem();
     }
 
-    /**
-     * @see https://php.net/countable.count
-     */
+    /** @see https://php.net/countable.count */
     public function count(): int
     {
         $this->exhaustIterator();
@@ -104,9 +102,7 @@ public function key()
         return $currentItem !== false ? $currentItem[self::FIELD_KEY] : null;
     }
 
-    /**
-     * @see https://php.net/iterator.next
-     */
+    /** @see https://php.net/iterator.next */
     public function next(): void
     {
         if (! $this->iteratorExhausted) {
@@ -121,9 +117,7 @@ public function next(): void
         next($this->items);
     }
 
-    /**
-     * @see https://php.net/iterator.rewind
-     */
+    /** @see https://php.net/iterator.rewind */
     public function rewind(): void
     {
         /* If the iterator has advanced, exhaust it now so that future iteration
@@ -136,9 +130,7 @@ public function rewind(): void
         reset($this->items);
     }
 
-    /**
-     * @see https://php.net/iterator.valid
-     */
+    /** @see https://php.net/iterator.valid */
     public function valid(): bool
     {
         return $this->key() !== null;
diff --git a/src/Model/CallbackIterator.php b/src/Model/CallbackIterator.php
index 8e3c68d0c..a900cd453 100644
--- a/src/Model/CallbackIterator.php
+++ b/src/Model/CallbackIterator.php
@@ -62,25 +62,19 @@ public function key()
         return $this->iterator->key();
     }
 
-    /**
-     * @see https://php.net/iterator.next
-     */
+    /** @see https://php.net/iterator.next */
     public function next(): void
     {
         $this->iterator->next();
     }
 
-    /**
-     * @see https://php.net/iterator.rewind
-     */
+    /** @see https://php.net/iterator.rewind */
     public function rewind(): void
     {
         $this->iterator->rewind();
     }
 
-    /**
-     * @see https://php.net/iterator.valid
-     */
+    /** @see https://php.net/iterator.valid */
     public function valid(): bool
     {
         return $this->iterator->valid();
diff --git a/src/Model/ChangeStreamIterator.php b/src/Model/ChangeStreamIterator.php
index ceb31f9fc..23dc33aa9 100644
--- a/src/Model/ChangeStreamIterator.php
+++ b/src/Model/ChangeStreamIterator.php
@@ -181,9 +181,7 @@ public function key()
         return $this->isValid ? parent::key() : null;
     }
 
-    /**
-     * @see https://php.net/iteratoriterator.rewind
-     */
+    /** @see https://php.net/iteratoriterator.rewind */
     public function next(): void
     {
         /* Determine if advancing the iterator will execute a getMore command
@@ -199,6 +197,7 @@ public function next(): void
 
         try {
             parent::next();
+
             $this->onIteration(! $getMore);
         } finally {
             if ($getMore) {
@@ -207,9 +206,7 @@ public function next(): void
         }
     }
 
-    /**
-     * @see https://php.net/iteratoriterator.rewind
-     */
+    /** @see https://php.net/iteratoriterator.rewind */
     public function rewind(): void
     {
         if ($this->isRewindNop) {
@@ -217,12 +214,11 @@ public function rewind(): void
         }
 
         parent::rewind();
+
         $this->onIteration(false);
     }
 
-    /**
-     * @see https://php.net/iteratoriterator.valid
-     */
+    /** @see https://php.net/iteratoriterator.valid */
     public function valid(): bool
     {
         return $this->isValid;
diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php
index 6722978bc..f7ab95846 100644
--- a/src/Model/CollectionInfo.php
+++ b/src/Model/CollectionInfo.php
@@ -39,9 +39,7 @@ class CollectionInfo implements ArrayAccess
     /** @var array */
     private $info;
 
-    /**
-     * @param array $info Collection info
-     */
+    /** @param array $info Collection info */
     public function __construct(array $info)
     {
         $this->info = $info;
diff --git a/src/Model/DatabaseInfo.php b/src/Model/DatabaseInfo.php
index 3f6326f7b..f09d9a129 100644
--- a/src/Model/DatabaseInfo.php
+++ b/src/Model/DatabaseInfo.php
@@ -38,9 +38,7 @@ class DatabaseInfo implements ArrayAccess
     /** @var array */
     private $info;
 
-    /**
-     * @param array $info Database info
-     */
+    /** @param array $info Database info */
     public function __construct(array $info)
     {
         $this->info = $info;
diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php
index 5e49568d2..590d1640e 100644
--- a/src/Model/IndexInfo.php
+++ b/src/Model/IndexInfo.php
@@ -44,9 +44,7 @@ class IndexInfo implements ArrayAccess
     /** @var array */
     private $info;
 
-    /**
-     * @param array $info Index info
-     */
+    /** @param array $info Index info */
     public function __construct(array $info)
     {
         $this->info = $info;
diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php
index 7b97dd0a9..7f19f143b 100644
--- a/src/Operation/MapReduce.php
+++ b/src/Operation/MapReduce.php
@@ -309,9 +309,7 @@ public function execute(Server $server)
         return new MapReduceResult($getIterator, $result);
     }
 
-    /**
-     * @param string|array|object $out
-     */
+    /** @param string|array|object $out */
     private function checkOutDeprecations($out): void
     {
         if (is_string($out)) {
diff --git a/src/Operation/WithTransaction.php b/src/Operation/WithTransaction.php
index e31b01b9e..f6c1057fb 100644
--- a/src/Operation/WithTransaction.php
+++ b/src/Operation/WithTransaction.php
@@ -10,9 +10,7 @@
 use function call_user_func;
 use function time;
 
-/**
- * @internal
- */
+/** @internal */
 class WithTransaction
 {
     /** @var callable */
diff --git a/tests/ClientTest.php b/tests/ClientTest.php
index 192868e75..de9705415 100644
--- a/tests/ClientTest.php
+++ b/tests/ClientTest.php
@@ -22,9 +22,7 @@ public function testConstructorDefaultUri(): void
         $this->assertEquals('mongodb://127.0.0.1/', (string) $client);
     }
 
-    /**
-     * @doesNotPerformAssertions
-     */
+    /** @doesNotPerformAssertions */
     public function testConstructorAutoEncryptionOpts(): void
     {
         $autoEncryptionOpts = [
@@ -36,9 +34,7 @@ public function testConstructorAutoEncryptionOpts(): void
         new Client(static::getUri(), [], ['autoEncryption' => $autoEncryptionOpts]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorDriverOptions
-     */
+    /** @dataProvider provideInvalidConstructorDriverOptions */
     public function testConstructorDriverOptionTypeChecks(array $driverOptions, string $exception = InvalidArgumentException::class): void
     {
         $this->expectException($exception);
diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php
index cd687bc0e..0310a0c2a 100644
--- a/tests/Collection/CollectionFunctionalTest.php
+++ b/tests/Collection/CollectionFunctionalTest.php
@@ -30,9 +30,7 @@
  */
 class CollectionFunctionalTest extends FunctionalTestCase
 {
-    /**
-     * @dataProvider provideInvalidDatabaseAndCollectionNames
-     */
+    /** @dataProvider provideInvalidDatabaseAndCollectionNames */
     public function testConstructorDatabaseNameArgument($databaseName, string $expectedExceptionClass): void
     {
         $this->expectException($expectedExceptionClass);
@@ -40,9 +38,7 @@ public function testConstructorDatabaseNameArgument($databaseName, string $expec
         new Collection($this->manager, $databaseName, $this->getCollectionName());
     }
 
-    /**
-     * @dataProvider provideInvalidDatabaseAndCollectionNames
-     */
+    /** @dataProvider provideInvalidDatabaseAndCollectionNames */
     public function testConstructorCollectionNameArgument($collectionName, string $expectedExceptionClass): void
     {
         $this->expectException($expectedExceptionClass);
@@ -58,9 +54,7 @@ public function provideInvalidDatabaseAndCollectionNames()
         ];
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -172,9 +166,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testDistinctWithTypeMap(array $typeMap, array $expectedDocuments): void
     {
         $bulkWrite = new BulkWrite(['ordered' => true]);
@@ -264,9 +256,7 @@ public function testDrop(): void
         $this->assertCollectionDoesNotExist($this->getCollectionName());
     }
 
-    /**
-     * @todo Move this to a unit test once Manager can be mocked
-     */
+    /** @todo Move this to a unit test once Manager can be mocked */
     public function testDropIndexShouldNotAllowWildcardCharacter(): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -732,9 +722,7 @@ function ($rw) {
         );
     }
 
-    /**
-     * @dataProvider collectionMethodClosures
-     */
+    /** @dataProvider collectionMethodClosures */
     public function testMethodDoesNotInheritReadWriteConcernInTranasaction(Closure $method): void
     {
         $this->skipIfTransactionsAreNotSupported();
@@ -760,9 +748,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider collectionWriteMethodClosures
-     */
+    /** @dataProvider collectionWriteMethodClosures */
     public function testMethodInTransactionWithWriteConcernOption($method): void
     {
         $this->skipIfTransactionsAreNotSupported();
@@ -782,9 +768,7 @@ public function testMethodInTransactionWithWriteConcernOption($method): void
         }
     }
 
-    /**
-     * @dataProvider collectionReadMethodClosures
-     */
+    /** @dataProvider collectionReadMethodClosures */
     public function testMethodInTransactionWithReadConcernOption($method): void
     {
         $this->skipIfTransactionsAreNotSupported();
diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php
index 4bb7ac174..6a81da1a6 100644
--- a/tests/Collection/CrudSpecFunctionalTest.php
+++ b/tests/Collection/CrudSpecFunctionalTest.php
@@ -52,9 +52,7 @@ public function setUp(): void
         $this->expectedCollection->drop();
     }
 
-    /**
-     * @dataProvider provideSpecificationTests
-     */
+    /** @dataProvider provideSpecificationTests */
     public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion, $serverless): void
     {
         if (isset($minServerVersion) || isset($maxServerVersion)) {
diff --git a/tests/Command/ListCollectionsTest.php b/tests/Command/ListCollectionsTest.php
index 8ea941a75..3cc5aa5e8 100644
--- a/tests/Command/ListCollectionsTest.php
+++ b/tests/Command/ListCollectionsTest.php
@@ -8,9 +8,7 @@
 
 class ListCollectionsTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Command/ListDatabasesTest.php b/tests/Command/ListDatabasesTest.php
index c1036ae94..90a5513f1 100644
--- a/tests/Command/ListDatabasesTest.php
+++ b/tests/Command/ListDatabasesTest.php
@@ -8,9 +8,7 @@
 
 class ListDatabasesTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php
index 6eb2f9fd1..1f5707911 100644
--- a/tests/Database/DatabaseFunctionalTest.php
+++ b/tests/Database/DatabaseFunctionalTest.php
@@ -21,9 +21,7 @@
  */
 class DatabaseFunctionalTest extends FunctionalTestCase
 {
-    /**
-     * @dataProvider provideInvalidDatabaseNames
-     */
+    /** @dataProvider provideInvalidDatabaseNames */
     public function testConstructorDatabaseNameArgument($databaseName, string $expectedExceptionClass): void
     {
         $this->expectException($expectedExceptionClass);
@@ -39,9 +37,7 @@ public function provideInvalidDatabaseNames()
         ];
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -138,9 +134,7 @@ public function testCommandAppliesTypeMapToCursor(): void
         $this->assertSame(1, (int) $commandResult['ok']);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testCommandCommandArgumentTypeCheck($command): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index d766ed8ea..1c580dcde 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -1690,9 +1690,7 @@ public function testSnapshotQueries(): void
         $salesCollection->drop();
     }
 
-    /**
-     * @doesNotPerformAssertions
-     */
+    /** @doesNotPerformAssertions */
     public function testVersionedApi(): void
     {
         $uriString = static::getUri(true);
@@ -1784,9 +1782,7 @@ public function testVersionedApiMigration(): void
         // phpcs:enable
     }
 
-    /**
-     * @doesNotPerformAssertions
-     */
+    /** @doesNotPerformAssertions */
     public function testWithTransactionExample(): void
     {
         $this->skipIfTransactionsAreNotSupported();
@@ -2003,9 +1999,7 @@ private function waitForSnapshot(string $databaseName, string $collectionName):
         } while (microtime(true) < $retryUntil);
     }
 
-    /**
-     * @see https://jira.mongodb.org/browse/SERVER-39704
-     */
+    /** @see https://jira.mongodb.org/browse/SERVER-39704 */
     private function preventStaleDbVersionError(string $databaseName, string $collectionName): void
     {
         $collection = new Collection($this->manager, $databaseName, $collectionName);
diff --git a/tests/Exception/InvalidArgumentExceptionTest.php b/tests/Exception/InvalidArgumentExceptionTest.php
index 0052c77b0..c4ab90a1d 100644
--- a/tests/Exception/InvalidArgumentExceptionTest.php
+++ b/tests/Exception/InvalidArgumentExceptionTest.php
@@ -8,9 +8,7 @@
 
 class InvalidArgumentExceptionTest extends TestCase
 {
-    /**
-     * @dataProvider provideExpectedTypes
-     */
+    /** @dataProvider provideExpectedTypes */
     public function testExpectedTypeFormatting($expectedType, $typeString): void
     {
         $e = InvalidArgumentException::invalidType('$arg', null, $expectedType);
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index d3ead4abc..6983313ac 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -20,9 +20,7 @@
  */
 class FunctionsTest extends TestCase
 {
-    /**
-     * @dataProvider provideDocumentAndTypeMap
-     */
+    /** @dataProvider provideDocumentAndTypeMap */
     public function testApplyTypeMapToDocument($document, array $typeMap, $expectedDocument): void
     {
         $this->assertEquals($expectedDocument, apply_type_map_to_document($document, $typeMap));
@@ -92,9 +90,7 @@ public function provideDocumentAndTypeMap()
         ];
     }
 
-    /**
-     * @dataProvider provideIndexSpecificationDocumentsAndGeneratedNames
-     */
+    /** @dataProvider provideIndexSpecificationDocumentsAndGeneratedNames */
     public function testGenerateIndexName($document, $expectedName): void
     {
         $this->assertSame($expectedName, generate_index_name($document));
@@ -111,18 +107,14 @@ public function provideIndexSpecificationDocumentsAndGeneratedNames()
         ];
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testGenerateIndexNameArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
         generate_index_name($document);
     }
 
-    /**
-     * @dataProvider provideIsFirstKeyOperatorDocuments
-     */
+    /** @dataProvider provideIsFirstKeyOperatorDocuments */
     public function testIsFirstKeyOperator($document, $isFirstKeyOperator): void
     {
         $this->assertSame($isFirstKeyOperator, is_first_key_operator($document));
@@ -140,18 +132,14 @@ public function provideIsFirstKeyOperatorDocuments()
         ];
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testIsFirstKeyOperatorArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
         is_first_key_operator($document);
     }
 
-    /**
-     * @dataProvider provideMapReduceOutValues
-     */
+    /** @dataProvider provideMapReduceOutValues */
     public function testIsMapReduceOutputInline($out, $isInline): void
     {
         $this->assertSame($isInline, is_mapreduce_output_inline($out));
@@ -167,9 +155,7 @@ public function provideMapReduceOutValues()
         ];
     }
 
-    /**
-     * @dataProvider provideTypeMapValues
-     */
+    /** @dataProvider provideTypeMapValues */
     public function testCreateFieldPathTypeMap(array $expected, array $typeMap, $fieldPath = 'field'): void
     {
         $this->assertEquals($expected, create_field_path_type_map($typeMap, $fieldPath));
@@ -229,9 +215,7 @@ public function provideTypeMapValues()
         ];
     }
 
-    /**
-     * @dataProvider providePipelines
-     */
+    /** @dataProvider providePipelines */
     public function testIsPipeline($expected, $pipeline): void
     {
         $this->assertSame($expected, is_pipeline($pipeline));
@@ -258,9 +242,7 @@ public function providePipelines()
         ];
     }
 
-    /**
-     * @dataProvider provideWriteConcerns
-     */
+    /** @dataProvider provideWriteConcerns */
     public function testIsWriteConcernAcknowledged($expected, WriteConcern $writeConcern): void
     {
         $this->assertSame($expected, is_write_concern_acknowledged($writeConcern));
diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php
index c59f4c128..97eb7317d 100644
--- a/tests/GridFS/BucketFunctionalTest.php
+++ b/tests/GridFS/BucketFunctionalTest.php
@@ -44,9 +44,7 @@
  */
 class BucketFunctionalTest extends FunctionalTestCase
 {
-    /**
-     * @doesNotPerformAssertions
-     */
+    /** @doesNotPerformAssertions */
     public function testValidConstructorOptions(): void
     {
         new Bucket($this->manager, $this->getDatabaseName(), [
@@ -58,9 +56,7 @@ public function testValidConstructorOptions(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -109,9 +105,7 @@ public function testConstructorShouldRequireChunkSizeBytesOptionToBePositive():
         new Bucket($this->manager, $this->getDatabaseName(), ['chunkSizeBytes' => 0]);
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedChunks
-     */
+    /** @dataProvider provideInputDataAndExpectedChunks */
     public function testDelete($input, $expectedChunks): void
     {
         $id = $this->bucket->uploadFromStream('filename', $this->createStream($input));
@@ -147,9 +141,7 @@ public function testDeleteShouldRequireFileToExist(): void
         $this->bucket->delete('nonexistent-id');
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedChunks
-     */
+    /** @dataProvider provideInputDataAndExpectedChunks */
     public function testDeleteStillRemovesChunksIfFileDoesNotExist($input, $expectedChunks): void
     {
         $id = $this->bucket->uploadFromStream('filename', $this->createStream($input));
@@ -207,9 +199,7 @@ public function testDownloadingFileWithUnexpectedChunkSize(): void
         stream_get_contents($this->bucket->openDownloadStream($id));
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedChunks
-     */
+    /** @dataProvider provideInputDataAndExpectedChunks */
     public function testDownloadToStream($input): void
     {
         $id = $this->bucket->uploadFromStream('filename', $this->createStream($input));
@@ -219,9 +209,7 @@ public function testDownloadToStream($input): void
         $this->assertStreamContents($input, $destination);
     }
 
-    /**
-     * @dataProvider provideInvalidStreamValues
-     */
+    /** @dataProvider provideInvalidStreamValues */
     public function testDownloadToStreamShouldRequireDestinationStream($destination): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -274,18 +262,14 @@ public function testDownloadToStreamByName(): void
         $this->assertStreamContents('baz', $destination);
     }
 
-    /**
-     * @dataProvider provideInvalidStreamValues
-     */
+    /** @dataProvider provideInvalidStreamValues */
     public function testDownloadToStreamByNameShouldRequireDestinationStream($destination): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->bucket->downloadToStreamByName('filename', $destination);
     }
 
-    /**
-     * @dataProvider provideNonexistentFilenameAndRevision
-     */
+    /** @dataProvider provideNonexistentFilenameAndRevision */
     public function testDownloadToStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision): void
     {
         $this->bucket->uploadFromStream('filename', $this->createStream('foo'));
@@ -452,9 +436,7 @@ public function testGetFileDocumentForStreamWithWritableStream(): void
         $this->assertSameDocument($metadata, $fileDocument->metadata);
     }
 
-    /**
-     * @dataProvider provideInvalidGridFSStreamValues
-     */
+    /** @dataProvider provideInvalidGridFSStreamValues */
     public function testGetFileDocumentForStreamShouldRequireGridFSStreamResource($stream): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -491,9 +473,7 @@ public function testGetFileIdForStreamWithWritableStream(): void
         $this->assertEquals(1, $this->bucket->getFileIdForStream($stream));
     }
 
-    /**
-     * @dataProvider provideInvalidGridFSStreamValues
-     */
+    /** @dataProvider provideInvalidGridFSStreamValues */
     public function testGetFileIdForStreamShouldRequireGridFSStreamResource($stream): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -508,9 +488,7 @@ public function testGetFilesCollection(): void
         $this->assertEquals('fs.files', $filesCollection->getCollectionName());
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedChunks
-     */
+    /** @dataProvider provideInputDataAndExpectedChunks */
     public function testOpenDownloadStream($input): void
     {
         $id = $this->bucket->uploadFromStream('filename', $this->createStream($input));
@@ -518,9 +496,7 @@ public function testOpenDownloadStream($input): void
         $this->assertStreamContents($input, $this->bucket->openDownloadStream($id));
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedChunks
-     */
+    /** @dataProvider provideInputDataAndExpectedChunks */
     public function testOpenDownloadStreamAndMultipleReadOperations($input): void
     {
         $id = $this->bucket->uploadFromStream('filename', $this->createStream($input));
@@ -566,9 +542,7 @@ public function testOpenDownloadStreamByName(): void
         $this->assertStreamContents('baz', $this->bucket->openDownloadStreamByName('filename', ['revision' => 2]));
     }
 
-    /**
-     * @dataProvider provideNonexistentFilenameAndRevision
-     */
+    /** @dataProvider provideNonexistentFilenameAndRevision */
     public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToExist($filename, $revision): void
     {
         $this->bucket->uploadFromStream('filename', $this->createStream('foo'));
@@ -588,9 +562,7 @@ public function testOpenUploadStream(): void
         $this->assertStreamContents('foobar', $this->bucket->openDownloadStreamByName('filename'));
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedChunks
-     */
+    /** @dataProvider provideInputDataAndExpectedChunks */
     public function testOpenUploadStreamAndMultipleWriteOperations($input): void
     {
         $stream = $this->bucket->openUploadStream('filename');
@@ -661,9 +633,7 @@ public function testUploadFromStream(): void
         $this->assertSameDocument(['foo' => 'bar'], $fileDocument['metadata']);
     }
 
-    /**
-     * @dataProvider provideInvalidStreamValues
-     */
+    /** @dataProvider provideInvalidStreamValues */
     public function testUploadFromStreamShouldRequireSourceStream($source): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/GridFS/ReadableStreamFunctionalTest.php b/tests/GridFS/ReadableStreamFunctionalTest.php
index 42c9ddae1..beabb7569 100644
--- a/tests/GridFS/ReadableStreamFunctionalTest.php
+++ b/tests/GridFS/ReadableStreamFunctionalTest.php
@@ -51,9 +51,7 @@ public function testGetFile(): void
         $this->assertSame($fileDocument, $stream->getFile());
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorFileDocuments
-     */
+    /** @dataProvider provideInvalidConstructorFileDocuments */
     public function testConstructorFileDocumentChecks($file): void
     {
         $this->expectException(CorruptFileException::class);
@@ -79,9 +77,7 @@ public function provideInvalidConstructorFileDocuments()
         return $options;
     }
 
-    /**
-     * @dataProvider provideFileIdAndExpectedBytes
-     */
+    /** @dataProvider provideFileIdAndExpectedBytes */
     public function testReadBytes($fileId, $length, $expectedBytes): void
     {
         $fileDocument = $this->collectionWrapper->findFileById($fileId);
@@ -126,9 +122,7 @@ function (array $args) {
         );
     }
 
-    /**
-     * @dataProvider provideFilteredFileIdAndExpectedBytes
-     */
+    /** @dataProvider provideFilteredFileIdAndExpectedBytes */
     public function testReadBytesCalledMultipleTimes($fileId, $length, $expectedBytes): void
     {
         $fileDocument = $this->collectionWrapper->findFileById($fileId);
@@ -206,9 +200,7 @@ public function testSeekOutOfRange(): void
         $stream->seek(11);
     }
 
-    /**
-     * @dataProvider providePreviousChunkSeekOffsetAndBytes
-     */
+    /** @dataProvider providePreviousChunkSeekOffsetAndBytes */
     public function testSeekPreviousChunk($offset, $length, $expectedBytes): void
     {
         $fileDocument = $this->collectionWrapper->findFileById('length-10');
@@ -242,9 +234,7 @@ public function providePreviousChunkSeekOffsetAndBytes()
         ];
     }
 
-    /**
-     * @dataProvider provideSameChunkSeekOffsetAndBytes
-     */
+    /** @dataProvider provideSameChunkSeekOffsetAndBytes */
     public function testSeekSameChunk($offset, $length, $expectedBytes): void
     {
         $fileDocument = $this->collectionWrapper->findFileById('length-10');
@@ -276,9 +266,7 @@ public function provideSameChunkSeekOffsetAndBytes()
         ];
     }
 
-    /**
-     * @dataProvider provideSubsequentChunkSeekOffsetAndBytes
-     */
+    /** @dataProvider provideSubsequentChunkSeekOffsetAndBytes */
     public function testSeekSubsequentChunk($offset, $length, $expectedBytes): void
     {
         $fileDocument = $this->collectionWrapper->findFileById('length-10');
diff --git a/tests/GridFS/WritableStreamFunctionalTest.php b/tests/GridFS/WritableStreamFunctionalTest.php
index 8a550bffc..6a11f64d4 100644
--- a/tests/GridFS/WritableStreamFunctionalTest.php
+++ b/tests/GridFS/WritableStreamFunctionalTest.php
@@ -23,9 +23,7 @@ public function setUp(): void
         $this->collectionWrapper = new CollectionWrapper($this->manager, $this->getDatabaseName(), 'fs');
     }
 
-    /**
-     * @doesNotPerformAssertions
-     */
+    /** @doesNotPerformAssertions */
     public function testValidConstructorOptions(): void
     {
         new WritableStream($this->collectionWrapper, 'filename', [
@@ -35,9 +33,7 @@ public function testValidConstructorOptions(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -86,9 +82,7 @@ public function testWriteBytesAlwaysUpdatesFileSize(): void
         $this->assertSame(1536, $stream->getSize());
     }
 
-    /**
-     * @dataProvider provideInputDataAndExpectedMD5
-     */
+    /** @dataProvider provideInputDataAndExpectedMD5 */
     public function testWriteBytesCalculatesMD5($input, $expectedMD5): void
     {
         $stream = new WritableStream($this->collectionWrapper, 'filename');
diff --git a/tests/Model/BSONIteratorTest.php b/tests/Model/BSONIteratorTest.php
index 69c2f9d26..9e208151b 100644
--- a/tests/Model/BSONIteratorTest.php
+++ b/tests/Model/BSONIteratorTest.php
@@ -14,9 +14,7 @@
 
 class BSONIteratorTest extends TestCase
 {
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testValidValues(?array $typeMap, $binaryString, array $expectedDocuments): void
     {
         $bsonIt = new BSONIterator($binaryString, ['typeMap' => $typeMap]);
diff --git a/tests/Model/ChangeStreamIteratorTest.php b/tests/Model/ChangeStreamIteratorTest.php
index 9be703bab..f596755fb 100644
--- a/tests/Model/ChangeStreamIteratorTest.php
+++ b/tests/Model/ChangeStreamIteratorTest.php
@@ -39,9 +39,7 @@ public function setUp(): void
         $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
     }
 
-    /**
-     * @dataProvider provideInvalidIntegerValues
-     */
+    /** @dataProvider provideInvalidIntegerValues */
     public function testFirstBatchArgumentTypeCheck($firstBatchSize): void
     {
         $this->expectException(TypeError::class);
@@ -60,18 +58,14 @@ public function testInitialResumeToken(): void
         $this->assertSameDocument((object) ['resumeToken' => 2], $iterator->getResumeToken());
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testInitialResumeTokenArgumentTypeCheck($initialResumeToken): void
     {
         $this->expectException(InvalidArgumentException::class);
         new ChangeStreamIterator($this->collection->find(), 0, $initialResumeToken, null);
     }
 
-    /**
-     * @dataProvider provideInvalidObjectValues
-     */
+    /** @dataProvider provideInvalidObjectValues */
     public function testPostBatchResumeTokenArgumentTypeCheck($postBatchResumeToken): void
     {
         $this->expectException(TypeError::class);
diff --git a/tests/Model/IndexInputTest.php b/tests/Model/IndexInputTest.php
index 673df1e5d..8babe75fd 100644
--- a/tests/Model/IndexInputTest.php
+++ b/tests/Model/IndexInputTest.php
@@ -22,9 +22,7 @@ public function testConstructorShouldRequireKeyToBeArrayOrObject(): void
         new IndexInput(['key' => 'foo']);
     }
 
-    /**
-     * @dataProvider provideInvalidFieldOrderValues
-     */
+    /** @dataProvider provideInvalidFieldOrderValues */
     public function testConstructorShouldRequireKeyFieldOrderToBeNumericOrString($order): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -42,9 +40,7 @@ public function testConstructorShouldRequireNameToBeString(): void
         new IndexInput(['key' => ['x' => 1], 'name' => 1]);
     }
 
-    /**
-     * @dataProvider provideExpectedNameAndKey
-     */
+    /** @dataProvider provideExpectedNameAndKey */
     public function testNameGeneration($expectedName, array $key): void
     {
         $this->assertSame($expectedName, (string) new IndexInput(['key' => $key]));
diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php
index d8b6c13af..ac0a2e767 100644
--- a/tests/Operation/AggregateFunctionalTest.php
+++ b/tests/Operation/AggregateFunctionalTest.php
@@ -157,9 +157,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testTypeMapOption(?array $typeMap, array $expectedDocuments): void
     {
         $this->createFixtures(3);
diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php
index db7a62b97..3ce450ad7 100644
--- a/tests/Operation/AggregateTest.php
+++ b/tests/Operation/AggregateTest.php
@@ -14,9 +14,7 @@ public function testConstructorPipelineArgumentMustBeAList(): void
         new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [1 => ['$match' => ['x' => 1]]]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php
index b935e5501..61d374168 100644
--- a/tests/Operation/BulkWriteFunctionalTest.php
+++ b/tests/Operation/BulkWriteFunctionalTest.php
@@ -163,9 +163,7 @@ public function testUnacknowledgedWriteConcern()
         return $result;
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesDeletedCount(BulkWriteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -173,9 +171,7 @@ public function testUnacknowledgedWriteConcernAccessesDeletedCount(BulkWriteResu
         $result->getDeletedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesInsertCount(BulkWriteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -183,9 +179,7 @@ public function testUnacknowledgedWriteConcernAccessesInsertCount(BulkWriteResul
         $result->getInsertedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesMatchedCount(BulkWriteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -193,9 +187,7 @@ public function testUnacknowledgedWriteConcernAccessesMatchedCount(BulkWriteResu
         $result->getMatchedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesModifiedCount(BulkWriteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -203,9 +195,7 @@ public function testUnacknowledgedWriteConcernAccessesModifiedCount(BulkWriteRes
         $result->getModifiedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesUpsertedCount(BulkWriteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -213,9 +203,7 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedCount(BulkWriteRes
         $result->getUpsertedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesUpsertedIds(BulkWriteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
diff --git a/tests/Operation/BulkWriteTest.php b/tests/Operation/BulkWriteTest.php
index aafaa4833..65a6ab7cb 100644
--- a/tests/Operation/BulkWriteTest.php
+++ b/tests/Operation/BulkWriteTest.php
@@ -53,9 +53,7 @@ public function testInsertOneDocumentArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testInsertOneDocumentArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -74,9 +72,7 @@ public function testDeleteManyFilterArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testDeleteManyFilterArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -86,9 +82,7 @@ public function testDeleteManyFilterArgumentTypeCheck($document): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testDeleteManyCollationOptionTypeCheck($collation): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -112,9 +106,7 @@ public function testDeleteOneFilterArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testDeleteOneFilterArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -124,9 +116,7 @@ public function testDeleteOneFilterArgumentTypeCheck($document): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testDeleteOneCollationOptionTypeCheck($collation): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -145,9 +135,7 @@ public function testReplaceOneFilterArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testReplaceOneFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -166,9 +154,7 @@ public function testReplaceOneReplacementArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testReplaceOneReplacementArgumentTypeCheck($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -187,9 +173,7 @@ public function testReplaceOneReplacementArgumentRequiresNoOperators(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testReplaceOneCollationOptionTypeCheck($collation): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -199,9 +183,7 @@ public function testReplaceOneCollationOptionTypeCheck($collation): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidBooleanValues
-     */
+    /** @dataProvider provideInvalidBooleanValues */
     public function testReplaceOneUpsertOptionTypeCheck($upsert): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -225,9 +207,7 @@ public function testUpdateManyFilterArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testUpdateManyFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -246,9 +226,7 @@ public function testUpdateManyUpdateArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testUpdateManyUpdateArgumentTypeCheck($update): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -267,9 +245,7 @@ public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidArrayValues
-     */
+    /** @dataProvider provideInvalidArrayValues */
     public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -279,9 +255,7 @@ public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testUpdateManyCollationOptionTypeCheck($collation): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -291,9 +265,7 @@ public function testUpdateManyCollationOptionTypeCheck($collation): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidBooleanValues
-     */
+    /** @dataProvider provideInvalidBooleanValues */
     public function testUpdateManyUpsertOptionTypeCheck($upsert): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -312,9 +284,7 @@ public function testUpdateOneFilterArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testUpdateOneFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -333,9 +303,7 @@ public function testUpdateOneUpdateArgumentMissing(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testUpdateOneUpdateArgumentTypeCheck($update): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -354,9 +322,7 @@ public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline(): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidArrayValues
-     */
+    /** @dataProvider provideInvalidArrayValues */
     public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -366,9 +332,7 @@ public function testUpdateOneArrayFiltersOptionTypeCheck($arrayFilters): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testUpdateOneCollationOptionTypeCheck($collation): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -378,9 +342,7 @@ public function testUpdateOneCollationOptionTypeCheck($collation): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidBooleanValues
-     */
+    /** @dataProvider provideInvalidBooleanValues */
     public function testUpdateOneUpsertOptionTypeCheck($upsert): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -390,9 +352,7 @@ public function testUpdateOneUpsertOptionTypeCheck($upsert): void
         ]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/CountDocumentsTest.php b/tests/Operation/CountDocumentsTest.php
index 650d45af2..3fcb9003a 100644
--- a/tests/Operation/CountDocumentsTest.php
+++ b/tests/Operation/CountDocumentsTest.php
@@ -7,18 +7,14 @@
 
 class CountDocumentsTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new CountDocuments($this->getDatabaseName(), $this->getCollectionName(), $filter);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/CountTest.php b/tests/Operation/CountTest.php
index 623717516..23969595c 100644
--- a/tests/Operation/CountTest.php
+++ b/tests/Operation/CountTest.php
@@ -7,18 +7,14 @@
 
 class CountTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new Count($this->getDatabaseName(), $this->getCollectionName(), $filter);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php
index 64b2f35db..c3e58b0a2 100644
--- a/tests/Operation/CreateCollectionTest.php
+++ b/tests/Operation/CreateCollectionTest.php
@@ -14,9 +14,7 @@ public function testConstructorPipelineOptionMustBeAList(): void
         new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['pipeline' => [1 => ['$match' => ['x' => 1]]]]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/CreateEncryptedCollectionTest.php b/tests/Operation/CreateEncryptedCollectionTest.php
index 86b5b03af..49d3f9c56 100644
--- a/tests/Operation/CreateEncryptedCollectionTest.php
+++ b/tests/Operation/CreateEncryptedCollectionTest.php
@@ -10,9 +10,7 @@
 
 class CreateEncryptedCollectionTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/CreateIndexesTest.php b/tests/Operation/CreateIndexesTest.php
index 1604b0c72..06a558eca 100644
--- a/tests/Operation/CreateIndexesTest.php
+++ b/tests/Operation/CreateIndexesTest.php
@@ -15,9 +15,7 @@ public function testConstructorIndexesArgumentMustBeAList(): void
         new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [1 => ['key' => ['x' => 1]]]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -54,9 +52,7 @@ public function testConstructorRequiresAtLeastOneIndex(): void
         new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), []);
     }
 
-    /**
-     * @dataProvider provideInvalidIndexSpecificationTypes
-     */
+    /** @dataProvider provideInvalidIndexSpecificationTypes */
     public function testConstructorRequiresIndexSpecificationsToBeAnArray($index): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DatabaseCommandTest.php b/tests/Operation/DatabaseCommandTest.php
index ffd3afa1f..29df6bd07 100644
--- a/tests/Operation/DatabaseCommandTest.php
+++ b/tests/Operation/DatabaseCommandTest.php
@@ -7,18 +7,14 @@
 
 class DatabaseCommandTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorCommandArgumentTypeCheck($command): void
     {
         $this->expectException(InvalidArgumentException::class);
         new DatabaseCommand($this->getDatabaseName(), $command);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php
index d97d53474..38166e2aa 100644
--- a/tests/Operation/DeleteFunctionalTest.php
+++ b/tests/Operation/DeleteFunctionalTest.php
@@ -117,9 +117,7 @@ public function testUnacknowledgedWriteConcern()
         return $result;
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesDeletedCount(DeleteResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
diff --git a/tests/Operation/DeleteTest.php b/tests/Operation/DeleteTest.php
index 859721f6d..acdbefc31 100644
--- a/tests/Operation/DeleteTest.php
+++ b/tests/Operation/DeleteTest.php
@@ -13,27 +13,21 @@
 
 class DeleteTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new Delete($this->getDatabaseName(), $this->getCollectionName(), $filter, 0);
     }
 
-    /**
-     * @dataProvider provideInvalidIntegerValues
-     */
+    /** @dataProvider provideInvalidIntegerValues */
     public function testConstructorLimitArgumentMustBeInt($limit): void
     {
         $this->expectException(TypeError::class);
         new Delete($this->getDatabaseName(), $this->getCollectionName(), [], $limit);
     }
 
-    /**
-     * @dataProvider provideInvalidLimitValues
-     */
+    /** @dataProvider provideInvalidLimitValues */
     public function testConstructorLimitArgumentMustBeOneOrZero($limit): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -46,9 +40,7 @@ public function provideInvalidLimitValues()
         return $this->wrapValuesForDataProvider([-1, 2]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DistinctFunctionalTest.php b/tests/Operation/DistinctFunctionalTest.php
index 8c02b80a0..c05b80f70 100644
--- a/tests/Operation/DistinctFunctionalTest.php
+++ b/tests/Operation/DistinctFunctionalTest.php
@@ -52,9 +52,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testTypeMapOption(array $typeMap, array $expectedDocuments): void
     {
         $bulkWrite = new BulkWrite(['ordered' => true]);
diff --git a/tests/Operation/DistinctTest.php b/tests/Operation/DistinctTest.php
index dc168bf91..8473e833d 100644
--- a/tests/Operation/DistinctTest.php
+++ b/tests/Operation/DistinctTest.php
@@ -7,18 +7,14 @@
 
 class DistinctTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', $filter);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DropCollectionFunctionalTest.php b/tests/Operation/DropCollectionFunctionalTest.php
index 29cd9ead4..08a5af222 100644
--- a/tests/Operation/DropCollectionFunctionalTest.php
+++ b/tests/Operation/DropCollectionFunctionalTest.php
@@ -41,9 +41,7 @@ public function testDropExistingCollection(): void
         $this->assertCollectionDoesNotExist($this->getCollectionName());
     }
 
-    /**
-     * @depends testDropExistingCollection
-     */
+    /** @depends testDropExistingCollection */
     public function testDropNonexistentCollection(): void
     {
         $this->assertCollectionDoesNotExist($this->getCollectionName());
diff --git a/tests/Operation/DropCollectionTest.php b/tests/Operation/DropCollectionTest.php
index 45042e6b9..cde87ae44 100644
--- a/tests/Operation/DropCollectionTest.php
+++ b/tests/Operation/DropCollectionTest.php
@@ -7,9 +7,7 @@
 
 class DropCollectionTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DropDatabaseFunctionalTest.php b/tests/Operation/DropDatabaseFunctionalTest.php
index 217bf1e63..8ee86b3b1 100644
--- a/tests/Operation/DropDatabaseFunctionalTest.php
+++ b/tests/Operation/DropDatabaseFunctionalTest.php
@@ -43,9 +43,7 @@ public function testDropExistingDatabase(): void
         $this->assertDatabaseDoesNotExist($server, $this->getDatabaseName());
     }
 
-    /**
-     * @depends testDropExistingDatabase
-     */
+    /** @depends testDropExistingDatabase */
     public function testDropNonexistentDatabase(): void
     {
         $server = $this->getPrimaryServer();
diff --git a/tests/Operation/DropDatabaseTest.php b/tests/Operation/DropDatabaseTest.php
index 06e33d961..fd3a527fd 100644
--- a/tests/Operation/DropDatabaseTest.php
+++ b/tests/Operation/DropDatabaseTest.php
@@ -7,9 +7,7 @@
 
 class DropDatabaseTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DropEncryptedCollectionTest.php b/tests/Operation/DropEncryptedCollectionTest.php
index 494f84daf..31a559efc 100644
--- a/tests/Operation/DropEncryptedCollectionTest.php
+++ b/tests/Operation/DropEncryptedCollectionTest.php
@@ -10,9 +10,7 @@
 
 class DropEncryptedCollectionTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/DropIndexesTest.php b/tests/Operation/DropIndexesTest.php
index ab09aeadf..03da89f84 100644
--- a/tests/Operation/DropIndexesTest.php
+++ b/tests/Operation/DropIndexesTest.php
@@ -13,9 +13,7 @@ public function testDropIndexShouldNotAllowEmptyIndexName(): void
         new DropIndexes($this->getDatabaseName(), $this->getCollectionName(), '');
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/EstimatedDocumentCountTest.php b/tests/Operation/EstimatedDocumentCountTest.php
index 803e1194d..485cb263e 100644
--- a/tests/Operation/EstimatedDocumentCountTest.php
+++ b/tests/Operation/EstimatedDocumentCountTest.php
@@ -7,9 +7,7 @@
 
 class EstimatedDocumentCountTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php
index 32f800f0e..5388f6752 100644
--- a/tests/Operation/ExplainFunctionalTest.php
+++ b/tests/Operation/ExplainFunctionalTest.php
@@ -26,9 +26,7 @@
 
 class ExplainFunctionalTest extends FunctionalTestCase
 {
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testCount($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -41,9 +39,7 @@ public function testCount($verbosity, $executionStatsExpected, $allPlansExecutio
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -58,9 +54,7 @@ public function testDelete($verbosity, $executionStatsExpected, $allPlansExecuti
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testDeleteMany($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -75,9 +69,7 @@ public function testDeleteMany($verbosity, $executionStatsExpected, $allPlansExe
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testDeleteOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -92,9 +84,7 @@ public function testDeleteOne($verbosity, $executionStatsExpected, $allPlansExec
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $operation = new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'x', []);
@@ -105,9 +95,7 @@ public function testDistinct($verbosity, $executionStatsExpected, $allPlansExecu
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testFindAndModify($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $operation = new FindAndModify($this->getDatabaseName(), $this->getCollectionName(), ['remove' => true]);
@@ -118,9 +106,7 @@ public function testFindAndModify($verbosity, $executionStatsExpected, $allPlans
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testFind($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -196,9 +182,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(1);
@@ -211,9 +195,7 @@ public function testFindOne($verbosity, $executionStatsExpected, $allPlansExecut
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $operation = new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), []);
@@ -224,9 +206,7 @@ public function testFindOneAndDelete($verbosity, $executionStatsExpected, $allPl
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $operation = new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1.1], ['x' => 5]);
@@ -237,9 +217,7 @@ public function testFindOneAndReplace($verbosity, $executionStatsExpected, $allP
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testFindOneAndUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $operation = new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], ['$rename' => ['x' => 'y']]);
@@ -250,9 +228,7 @@ public function testFindOneAndUpdate($verbosity, $executionStatsExpected, $allPl
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testUpdate($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -321,9 +297,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testUpdateMany($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -339,9 +313,7 @@ public function testUpdateMany($verbosity, $executionStatsExpected, $allPlansExe
         $this->assertExplainResult($result, $executionStatsExpected, $allPlansExecutionExpected);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testUpdateOne($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         $this->createFixtures(3);
@@ -375,9 +347,7 @@ public function testAggregate(): void
         $this->assertExplainResult($result, false, false, true);
     }
 
-    /**
-     * @dataProvider provideVerbosityInformation
-     */
+    /** @dataProvider provideVerbosityInformation */
     public function testAggregateOptimizedToQuery($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
         if (version_compare($this->getServerVersion(), '4.2.0', '<')) {
diff --git a/tests/Operation/ExplainTest.php b/tests/Operation/ExplainTest.php
index 184705662..a77f39129 100644
--- a/tests/Operation/ExplainTest.php
+++ b/tests/Operation/ExplainTest.php
@@ -8,9 +8,7 @@
 
 class ExplainTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $explainable = $this->getMockBuilder(Explainable::class)->getMock();
diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php
index bc89fb524..d90c4d930 100644
--- a/tests/Operation/FindAndModifyFunctionalTest.php
+++ b/tests/Operation/FindAndModifyFunctionalTest.php
@@ -15,9 +15,7 @@
 
 class FindAndModifyFunctionalTest extends FunctionalTestCase
 {
-    /**
-     * @see https://jira.mongodb.org/browse/PHPLIB-344
-     */
+    /** @see https://jira.mongodb.org/browse/PHPLIB-344 */
     public function testManagerReadConcernIsOmitted(): void
     {
         $manager = static::createTestManager(null, ['readConcernLevel' => 'majority']);
@@ -167,9 +165,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocument
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocument */
     public function testTypeMapOption(?array $typeMap, $expectedDocument): void
     {
         $this->createFixtures(1);
diff --git a/tests/Operation/FindAndModifyTest.php b/tests/Operation/FindAndModifyTest.php
index 4506d59e8..3904385e9 100644
--- a/tests/Operation/FindAndModifyTest.php
+++ b/tests/Operation/FindAndModifyTest.php
@@ -7,9 +7,7 @@
 
 class FindAndModifyTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php
index 5ff55752b..6ea8b5840 100644
--- a/tests/Operation/FindFunctionalTest.php
+++ b/tests/Operation/FindFunctionalTest.php
@@ -102,9 +102,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testTypeMapOption(array $typeMap, array $expectedDocuments): void
     {
         $this->createFixtures(3);
diff --git a/tests/Operation/FindOneAndDeleteTest.php b/tests/Operation/FindOneAndDeleteTest.php
index c2a325e6f..42055ba27 100644
--- a/tests/Operation/FindOneAndDeleteTest.php
+++ b/tests/Operation/FindOneAndDeleteTest.php
@@ -7,18 +7,14 @@
 
 class FindOneAndDeleteTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), $filter);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/FindOneAndReplaceTest.php b/tests/Operation/FindOneAndReplaceTest.php
index ad7cbd36b..50ae76e75 100644
--- a/tests/Operation/FindOneAndReplaceTest.php
+++ b/tests/Operation/FindOneAndReplaceTest.php
@@ -7,18 +7,14 @@
 
 class FindOneAndReplaceTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), $filter, []);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorReplacementArgumentTypeCheck($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -32,9 +28,7 @@ public function testConstructorReplacementArgumentRequiresNoOperators(): void
         new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], ['$set' => ['x' => 1]]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -56,9 +50,7 @@ public function provideInvalidConstructorOptions()
         return $options;
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorReturnDocumentOptions
-     */
+    /** @dataProvider provideInvalidConstructorReturnDocumentOptions */
     public function testConstructorReturnDocumentOption($returnDocument): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/FindOneAndUpdateTest.php b/tests/Operation/FindOneAndUpdateTest.php
index 8bf142148..1ba51f166 100644
--- a/tests/Operation/FindOneAndUpdateTest.php
+++ b/tests/Operation/FindOneAndUpdateTest.php
@@ -7,18 +7,14 @@
 
 class FindOneAndUpdateTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), $filter, []);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorUpdateArgumentTypeCheck($update): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -32,9 +28,7 @@ public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline(): void
         new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], []);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -56,9 +50,7 @@ public function provideInvalidConstructorOptions()
         return $options;
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorReturnDocumentOptions
-     */
+    /** @dataProvider provideInvalidConstructorReturnDocumentOptions */
     public function testConstructorReturnDocumentOption($returnDocument): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/FindOneFunctionalTest.php b/tests/Operation/FindOneFunctionalTest.php
index cd1096fa7..d18d056e3 100644
--- a/tests/Operation/FindOneFunctionalTest.php
+++ b/tests/Operation/FindOneFunctionalTest.php
@@ -7,9 +7,7 @@
 
 class FindOneFunctionalTest extends FunctionalTestCase
 {
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocument
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocument */
     public function testTypeMapOption(array $typeMap, $expectedDocument): void
     {
         $this->createFixtures(1);
diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php
index c8bc59647..f5889f260 100644
--- a/tests/Operation/FindTest.php
+++ b/tests/Operation/FindTest.php
@@ -7,18 +7,14 @@
 
 class FindTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new Find($this->getDatabaseName(), $this->getCollectionName(), $filter);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -147,9 +143,7 @@ private function getInvalidHintValues()
         return [123, 3.14, true];
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorCursorTypeOptions
-     */
+    /** @dataProvider provideInvalidConstructorCursorTypeOptions */
     public function testConstructorCursorTypeOption($cursorType): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/InsertManyFunctionalTest.php b/tests/Operation/InsertManyFunctionalTest.php
index e35905f2d..533cd8fce 100644
--- a/tests/Operation/InsertManyFunctionalTest.php
+++ b/tests/Operation/InsertManyFunctionalTest.php
@@ -125,9 +125,7 @@ public function testUnacknowledgedWriteConcern()
         return $result;
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertManyResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -135,9 +133,7 @@ public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertManyRe
         $result->getInsertedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertManyResult $result): void
     {
         $this->assertInstanceOf(ObjectId::class, $result->getInsertedIds()[0]);
diff --git a/tests/Operation/InsertManyTest.php b/tests/Operation/InsertManyTest.php
index e8326f100..eb283a970 100644
--- a/tests/Operation/InsertManyTest.php
+++ b/tests/Operation/InsertManyTest.php
@@ -21,9 +21,7 @@ public function testConstructorDocumentsMustBeAList(): void
         new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [1 => ['x' => 1]]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorDocumentsArgumentElementTypeChecks($document): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -31,9 +29,7 @@ public function testConstructorDocumentsArgumentElementTypeChecks($document): vo
         new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [$document]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/InsertOneFunctionalTest.php b/tests/Operation/InsertOneFunctionalTest.php
index 1aa1790b7..93bc26cb5 100644
--- a/tests/Operation/InsertOneFunctionalTest.php
+++ b/tests/Operation/InsertOneFunctionalTest.php
@@ -23,9 +23,7 @@ public function setUp(): void
         $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
     }
 
-    /**
-     * @dataProvider provideDocumentWithExistingId
-     */
+    /** @dataProvider provideDocumentWithExistingId */
     public function testInsertOneWithExistingId($document): void
     {
         $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document);
@@ -140,9 +138,7 @@ public function testUnacknowledgedWriteConcern()
         return $result;
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertOneResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -150,9 +146,7 @@ public function testUnacknowledgedWriteConcernAccessesInsertedCount(InsertOneRes
         $result->getInsertedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesInsertedId(InsertOneResult $result): void
     {
         $this->assertInstanceOf(ObjectId::class, $result->getInsertedId());
diff --git a/tests/Operation/InsertOneTest.php b/tests/Operation/InsertOneTest.php
index f957ba9d3..c51faea85 100644
--- a/tests/Operation/InsertOneTest.php
+++ b/tests/Operation/InsertOneTest.php
@@ -7,18 +7,14 @@
 
 class InsertOneTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorDocumentArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
         new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/ListIndexesTest.php b/tests/Operation/ListIndexesTest.php
index dd4c8978d..aa3b75e7a 100644
--- a/tests/Operation/ListIndexesTest.php
+++ b/tests/Operation/ListIndexesTest.php
@@ -7,9 +7,7 @@
 
 class ListIndexesTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php
index d47109b03..c58e42138 100644
--- a/tests/Operation/MapReduceFunctionalTest.php
+++ b/tests/Operation/MapReduceFunctionalTest.php
@@ -220,9 +220,7 @@ function (array $event): void {
         );
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testTypeMapOptionWithInlineResults(?array $typeMap, array $expectedDocuments): void
     {
         $this->createFixtures(3);
@@ -267,9 +265,7 @@ public function provideTypeMapOptionsAndExpectedDocuments()
         ];
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedDocuments
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedDocuments */
     public function testTypeMapOptionWithOutputCollection(?array $typeMap, array $expectedDocuments): void
     {
         $this->createFixtures(3);
diff --git a/tests/Operation/MapReduceTest.php b/tests/Operation/MapReduceTest.php
index 1376362db..88d4a77fd 100644
--- a/tests/Operation/MapReduceTest.php
+++ b/tests/Operation/MapReduceTest.php
@@ -10,9 +10,7 @@
 
 class MapReduceTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidOutValues
-     */
+    /** @dataProvider provideInvalidOutValues */
     public function testConstructorOutArgumentTypeCheck($out): void
     {
         $map = new Javascript('function() { emit(this.x, this.y); }');
@@ -27,9 +25,7 @@ public function provideInvalidOutValues()
         return $this->wrapValuesForDataProvider([123, 3.14, true]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $map = new Javascript('function() { emit(this.x, this.y); }');
diff --git a/tests/Operation/ModifyCollectionTest.php b/tests/Operation/ModifyCollectionTest.php
index 2faed3e1f..4fcda8b72 100644
--- a/tests/Operation/ModifyCollectionTest.php
+++ b/tests/Operation/ModifyCollectionTest.php
@@ -14,9 +14,7 @@ public function testConstructorEmptyCollectionOptions(): void
         new ModifyCollection($this->getDatabaseName(), $this->getCollectionName(), []);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/RenameCollectionTest.php b/tests/Operation/RenameCollectionTest.php
index f25eea78d..e13402147 100644
--- a/tests/Operation/RenameCollectionTest.php
+++ b/tests/Operation/RenameCollectionTest.php
@@ -7,9 +7,7 @@
 
 class RenameCollectionTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/ReplaceOneTest.php b/tests/Operation/ReplaceOneTest.php
index 21b6a396c..bf73029d2 100644
--- a/tests/Operation/ReplaceOneTest.php
+++ b/tests/Operation/ReplaceOneTest.php
@@ -8,18 +8,14 @@
 
 class ReplaceOneTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), $filter, ['y' => 1]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorReplacementArgumentTypeCheck($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -35,9 +31,7 @@ public function testConstructorReplacementArgument($replacement): void
         new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
     }
 
-    /**
-     * @dataProvider provideUpdateDocuments
-     */
+    /** @dataProvider provideUpdateDocuments */
     public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php
index c0b6ba76a..8fcd7c5f0 100644
--- a/tests/Operation/UpdateFunctionalTest.php
+++ b/tests/Operation/UpdateFunctionalTest.php
@@ -225,9 +225,7 @@ public function testUnacknowledgedWriteConcern()
         return $result;
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesMatchedCount(UpdateResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -235,9 +233,7 @@ public function testUnacknowledgedWriteConcernAccessesMatchedCount(UpdateResult
         $result->getMatchedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesModifiedCount(UpdateResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -245,9 +241,7 @@ public function testUnacknowledgedWriteConcernAccessesModifiedCount(UpdateResult
         $result->getModifiedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesUpsertedCount(UpdateResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
@@ -255,9 +249,7 @@ public function testUnacknowledgedWriteConcernAccessesUpsertedCount(UpdateResult
         $result->getUpsertedCount();
     }
 
-    /**
-     * @depends testUnacknowledgedWriteConcern
-     */
+    /** @depends testUnacknowledgedWriteConcern */
     public function testUnacknowledgedWriteConcernAccessesUpsertedId(UpdateResult $result): void
     {
         $this->expectException(BadMethodCallException::class);
diff --git a/tests/Operation/UpdateManyTest.php b/tests/Operation/UpdateManyTest.php
index cf1d770a6..4636431da 100644
--- a/tests/Operation/UpdateManyTest.php
+++ b/tests/Operation/UpdateManyTest.php
@@ -8,18 +8,14 @@
 
 class UpdateManyTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorUpdateArgumentTypeCheck($update): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -35,9 +31,7 @@ public function testConstructorUpdateArgument($update): void
         new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    /**
-     * @dataProvider provideReplacementDocuments
-     */
+    /** @dataProvider provideReplacementDocuments */
     public function testConstructorUpdateArgumentRequiresOperators($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/UpdateOneTest.php b/tests/Operation/UpdateOneTest.php
index 9933692d8..b7164ebc5 100644
--- a/tests/Operation/UpdateOneTest.php
+++ b/tests/Operation/UpdateOneTest.php
@@ -8,18 +8,14 @@
 
 class UpdateOneTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
         new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorUpdateArgumentTypeCheck($update): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -35,9 +31,7 @@ public function testConstructorUpdateArgument($update): void
         new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    /**
-     * @dataProvider provideReplacementDocuments
-     */
+    /** @dataProvider provideReplacementDocuments */
     public function testConstructorUpdateArgumentRequiresOperators($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/UpdateTest.php b/tests/Operation/UpdateTest.php
index 2e3773d34..e7fe97898 100644
--- a/tests/Operation/UpdateTest.php
+++ b/tests/Operation/UpdateTest.php
@@ -7,9 +7,7 @@
 
 class UpdateTest extends TestCase
 {
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorFilterArgumentTypeCheck($filter): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -17,9 +15,7 @@ public function testConstructorFilterArgumentTypeCheck($filter): void
         new Update($this->getDatabaseName(), $this->getCollectionName(), $filter, ['$set' => ['x' => 1]]);
     }
 
-    /**
-     * @dataProvider provideInvalidDocumentValues
-     */
+    /** @dataProvider provideInvalidDocumentValues */
     public function testConstructorUpdateArgumentTypeCheck($update): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -27,9 +23,7 @@ public function testConstructorUpdateArgumentTypeCheck($update): void
         new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php
index 0a5671379..cae3d850a 100644
--- a/tests/Operation/WatchFunctionalTest.php
+++ b/tests/Operation/WatchFunctionalTest.php
@@ -1008,9 +1008,7 @@ public function testStartAfterOption(): void
         $this->assertMatchesDocument($expectedResult, $changeStream->current());
     }
 
-    /**
-     * @dataProvider provideTypeMapOptionsAndExpectedChangeDocument
-     */
+    /** @dataProvider provideTypeMapOptionsAndExpectedChangeDocument */
     public function testTypeMapOption(array $typeMap, $expectedChangeDocument): void
     {
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], ['typeMap' => $typeMap] + $this->defaultOptions);
diff --git a/tests/Operation/WatchTest.php b/tests/Operation/WatchTest.php
index d4d1be19c..64c490fa2 100644
--- a/tests/Operation/WatchTest.php
+++ b/tests/Operation/WatchTest.php
@@ -31,9 +31,7 @@ public function testConstructorPipelineArgumentMustBeAList(): void
         new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), ['foo' => ['$match' => ['x' => 1]]]);
     }
 
-    /**
-     * @dataProvider provideInvalidConstructorOptions
-     */
+    /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
         $this->expectException(InvalidArgumentException::class);
diff --git a/tests/PedantryTest.php b/tests/PedantryTest.php
index 5e4cbf631..2885d82a7 100644
--- a/tests/PedantryTest.php
+++ b/tests/PedantryTest.php
@@ -24,9 +24,7 @@
  */
 class PedantryTest extends TestCase
 {
-    /**
-     * @dataProvider provideProjectClassNames
-     */
+    /** @dataProvider provideProjectClassNames */
     public function testMethodsAreOrderedAlphabeticallyByVisibility($className): void
     {
         $class = new ReflectionClass($className);
diff --git a/tests/SpecTests/DocumentsMatchConstraintTest.php b/tests/SpecTests/DocumentsMatchConstraintTest.php
index 4e7e3203a..bd61a9354 100644
--- a/tests/SpecTests/DocumentsMatchConstraintTest.php
+++ b/tests/SpecTests/DocumentsMatchConstraintTest.php
@@ -72,9 +72,7 @@ public function testIgnoreExtraKeysInEmbedded(): void
         $this->assertResult(false, $c, [1, ['a' => 2]], 'Keys must have the correct value');
     }
 
-    /**
-     * @dataProvider provideBSONTypes
-     */
+    /** @dataProvider provideBSONTypes */
     public function testBSONTypeAssertions($type, $value): void
     {
         $constraint = new DocumentsMatchConstraint(['x' => ['$$type' => $type]]);
@@ -136,9 +134,7 @@ public function testBSONTypeAssertionsWithMultipleTypes(): void
         $this->assertResult(false, $c2, ['x' => true], 'bool is not number or string');
     }
 
-    /**
-     * @dataProvider errorMessageProvider
-     */
+    /** @dataProvider errorMessageProvider */
     public function testErrorMessages($expectedMessagePart, DocumentsMatchConstraint $constraint, $actualValue): void
     {
         try {
diff --git a/tests/SpecTests/ErrorExpectation.php b/tests/SpecTests/ErrorExpectation.php
index 55ee97cc1..56d271427 100644
--- a/tests/SpecTests/ErrorExpectation.php
+++ b/tests/SpecTests/ErrorExpectation.php
@@ -118,9 +118,7 @@ public static function fromRetryableWrites(stdClass $outcome)
         return $o;
     }
 
-    /**
-     * @throws InvalidArgumentException
-     */
+    /** @throws InvalidArgumentException */
     public static function fromTransactions(stdClass $operation)
     {
         return self::fromGenericOperation($operation);
@@ -210,9 +208,7 @@ private function assertCodeName(TestCase $test, ?Throwable $actual = null): void
         $test->assertSame($this->codeName, $result->codeName);
     }
 
-    /**
-     * @throws InvalidArgumentException
-     */
+    /** @throws InvalidArgumentException */
     private static function fromGenericOperation(stdClass $operation)
     {
         $o = new self();
diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php
index 42d9da990..eb5c343c7 100644
--- a/tests/SpecTests/Operation.php
+++ b/tests/SpecTests/Operation.php
@@ -666,9 +666,7 @@ function (IndexInfo $indexInfo) {
         );
     }
 
-    /**
-     * @throws LogicException if the operation object is unsupported
-     */
+    /** @throws LogicException if the operation object is unsupported */
     private function getResultAssertionType()
     {
         switch ($this->object) {
@@ -694,9 +692,7 @@ private function getResultAssertionType()
         }
     }
 
-    /**
-     * @throws LogicException if the collection operation is unsupported
-     */
+    /** @throws LogicException if the collection operation is unsupported */
     private function getResultAssertionTypeForClient()
     {
         switch ($this->name) {
@@ -714,9 +710,7 @@ private function getResultAssertionTypeForClient()
         }
     }
 
-    /**
-     * @throws LogicException if the collection operation is unsupported
-     */
+    /** @throws LogicException if the collection operation is unsupported */
     private function getResultAssertionTypeForCollection()
     {
         switch ($this->name) {
@@ -787,9 +781,7 @@ private function getResultAssertionTypeForCollection()
         }
     }
 
-    /**
-     * @throws LogicException if the database operation is unsupported
-     */
+    /** @throws LogicException if the database operation is unsupported */
     private function getResultAssertionTypeForDatabase()
     {
         switch ($this->name) {
diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php
index 48aa55cc0..1d83faaba 100644
--- a/tests/SpecTests/PrimaryStepDownSpecTest.php
+++ b/tests/SpecTests/PrimaryStepDownSpecTest.php
@@ -17,9 +17,7 @@
 use function current;
 use function sprintf;
 
-/**
- * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests
- */
+/** @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests */
 class PrimaryStepDownSpecTest extends FunctionalTestCase
 {
     public const INTERRUPTED_AT_SHUTDOWN = 11600;
@@ -42,9 +40,7 @@ public function setUp(): void
         $this->collection = $this->client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 
-    /**
-     * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#not-primary-keep-connection-pool
-     */
+    /** @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#not-primary-keep-connection-pool */
     public function testNotPrimaryKeepsConnectionPool(): void
     {
         $runOn = [(object) ['minServerVersion' => '4.1.11', 'topology' => [self::TOPOLOGY_REPLICASET]]];
@@ -78,9 +74,7 @@ public function testNotPrimaryKeepsConnectionPool(): void
         $this->assertSame($totalConnectionsCreated, $this->getTotalConnectionsCreated());
     }
 
-    /**
-     * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#not-primary-reset-connection-pool
-     */
+    /** @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#not-primary-reset-connection-pool */
     public function testNotPrimaryResetConnectionPool(): void
     {
         $runOn = [(object) ['minServerVersion' => '4.0.0', 'maxServerVersion' => '4.0.999', 'topology' => [self::TOPOLOGY_REPLICASET]]];
@@ -117,9 +111,7 @@ public function testNotPrimaryResetConnectionPool(): void
         $this->assertSame(1, $result->getInsertedCount());
     }
 
-    /**
-     * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#shutdown-in-progress-reset-connection-pool
-     */
+    /** @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#shutdown-in-progress-reset-connection-pool */
     public function testShutdownResetConnectionPool(): void
     {
         $runOn = [(object) ['minServerVersion' => '4.0.0']];
@@ -156,9 +148,7 @@ public function testShutdownResetConnectionPool(): void
         $this->assertSame(1, $result->getInsertedCount());
     }
 
-    /**
-     * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#interrupted-at-shutdown-reset-connection-pool
-     */
+    /** @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#interrupted-at-shutdown-reset-connection-pool */
     public function testInterruptedAtShutdownResetConnectionPool(): void
     {
         $runOn = [(object) ['minServerVersion' => '4.0.0']];
@@ -195,9 +185,7 @@ public function testInterruptedAtShutdownResetConnectionPool(): void
         $this->assertSame(1, $result->getInsertedCount());
     }
 
-    /**
-     * @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#getmore-iteration
-     */
+    /** @see https://github.com/mongodb/specifications/tree/master/source/connections-survive-step-down/tests#getmore-iteration */
     public function testGetMoreIteration(): void
     {
         $this->markTestSkipped('Test causes subsequent failures in other tests (see PHPLIB-471)');
diff --git a/tests/SpecTests/ReadWriteConcernSpecTest.php b/tests/SpecTests/ReadWriteConcernSpecTest.php
index 96560a86a..ae5ec27f1 100644
--- a/tests/SpecTests/ReadWriteConcernSpecTest.php
+++ b/tests/SpecTests/ReadWriteConcernSpecTest.php
@@ -9,9 +9,7 @@
 use function file_get_contents;
 use function glob;
 
-/**
- * @see https://github.com/mongodb/specifications/tree/master/source/read-write-concern
- */
+/** @see https://github.com/mongodb/specifications/tree/master/source/read-write-concern */
 class ReadWriteConcernSpecTest extends FunctionalTestCase
 {
     /** @var array */
diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php
index 134b0249a..caca6c013 100644
--- a/tests/SpecTests/TransactionsSpecTest.php
+++ b/tests/SpecTests/TransactionsSpecTest.php
@@ -124,9 +124,7 @@ public function provideTransactionsTests(): array
         return $this->provideTests('transactions');
     }
 
-    /**
-     * @dataProvider provideTransactionsConvenientApiTests
-     */
+    /** @dataProvider provideTransactionsConvenientApiTests */
     public function testTransactionsConvenientApi(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void
     {
         $this->runTransactionTest($test, $runOn, $data, $databaseName, $collectionName);
diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
index c45f981e9..6bace1633 100644
--- a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
+++ b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
@@ -28,9 +28,7 @@
 
 class IsBsonTypeTest extends TestCase
 {
-    /**
-     * @dataProvider provideTypes
-     */
+    /** @dataProvider provideTypes */
     public function testConstraint($type, $value): void
     {
         $this->assertResult(true, new IsBsonType($type), $value, $this->dataName() . ' is ' . $type);
@@ -79,9 +77,7 @@ public function provideTypes()
         ];
     }
 
-    /**
-     * @dataProvider provideTypes
-     */
+    /** @dataProvider provideTypes */
     public function testAny($type, $value): void
     {
         $this->assertResult(true, IsBsonType::any(), $value, $this->dataName() . ' is a BSON type');
diff --git a/tests/UnifiedSpecTests/Constraint/MatchesTest.php b/tests/UnifiedSpecTests/Constraint/MatchesTest.php
index 72433b3e0..53a7643a4 100644
--- a/tests/UnifiedSpecTests/Constraint/MatchesTest.php
+++ b/tests/UnifiedSpecTests/Constraint/MatchesTest.php
@@ -170,9 +170,7 @@ public function testOperatorSessionLsid(): void
         $this->assertResult(false, $c, ['x' => 1], 'session LSID does not match (embedded)');
     }
 
-    /**
-     * @dataProvider errorMessageProvider
-     */
+    /** @dataProvider errorMessageProvider */
     public function testErrorMessages($expectedMessageRegex, Matches $constraint, $actualValue): void
     {
         try {
@@ -255,9 +253,7 @@ public function errorMessageProvider()
         ];
     }
 
-    /**
-     * @dataProvider operatorErrorMessageProvider
-     */
+    /** @dataProvider operatorErrorMessageProvider */
     public function testOperatorSyntaxValidation($expectedMessage, Matches $constraint): void
     {
         $this->expectException(ExpectationFailedException::class);
diff --git a/tests/UnifiedSpecTests/EntityMap.php b/tests/UnifiedSpecTests/EntityMap.php
index 3e50f574b..0eaddb53f 100644
--- a/tests/UnifiedSpecTests/EntityMap.php
+++ b/tests/UnifiedSpecTests/EntityMap.php
@@ -57,9 +57,7 @@ public function __destruct()
         }
     }
 
-    /**
-     * @see https://php.net/arrayaccess.offsetexists
-     */
+    /** @see https://php.net/arrayaccess.offsetexists */
     public function offsetExists($id): bool
     {
         assertIsString($id);
@@ -80,17 +78,13 @@ public function offsetGet($id)
         return $this->map[$id]->value;
     }
 
-    /**
-     * @see https://php.net/arrayaccess.offsetset
-     */
+    /** @see https://php.net/arrayaccess.offsetset */
     public function offsetSet($id, $value): void
     {
         Assert::fail('Entities can only be set via set()');
     }
 
-    /**
-     * @see https://php.net/arrayaccess.offsetunset
-     */
+    /** @see https://php.net/arrayaccess.offsetunset */
     public function offsetUnset($id): void
     {
         Assert::fail('Entities cannot be removed from the map');
diff --git a/tests/UnifiedSpecTests/EventCollector.php b/tests/UnifiedSpecTests/EventCollector.php
index 98465a1a3..8ffcd6287 100644
--- a/tests/UnifiedSpecTests/EventCollector.php
+++ b/tests/UnifiedSpecTests/EventCollector.php
@@ -80,25 +80,19 @@ public function __construct(BSONArray $eventList, array $collectEvents, string $
         $this->eventList = $eventList;
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */
     public function commandFailed(CommandFailedEvent $event): void
     {
         $this->handleCommandMonitoringEvent($event);
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */
     public function commandStarted(CommandStartedEvent $event): void
     {
         $this->handleCommandMonitoringEvent($event);
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */
     public function commandSucceeded(CommandSucceededEvent $event): void
     {
         $this->handleCommandMonitoringEvent($event);
diff --git a/tests/UnifiedSpecTests/EventObserver.php b/tests/UnifiedSpecTests/EventObserver.php
index 842dfb89a..6995dd995 100644
--- a/tests/UnifiedSpecTests/EventObserver.php
+++ b/tests/UnifiedSpecTests/EventObserver.php
@@ -150,25 +150,19 @@ public function __construct(array $observeEvents, array $ignoreCommands, bool $o
         $this->context = $context;
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */
     public function commandFailed(CommandFailedEvent $event): void
     {
         $this->handleEvent($event);
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */
     public function commandStarted(CommandStartedEvent $event): void
     {
         $this->handleEvent($event);
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */
     public function commandSucceeded(CommandSucceededEvent $event): void
     {
         $this->handleEvent($event);
diff --git a/tests/UnifiedSpecTests/FailPointObserver.php b/tests/UnifiedSpecTests/FailPointObserver.php
index 76d3b9633..7f8c3a9e6 100644
--- a/tests/UnifiedSpecTests/FailPointObserver.php
+++ b/tests/UnifiedSpecTests/FailPointObserver.php
@@ -16,16 +16,12 @@ class FailPointObserver implements CommandSubscriber
     /** @var array */
     private $failPointsAndServers = [];
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandfailed.php */
     public function commandFailed(CommandFailedEvent $event): void
     {
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandstarted.php */
     public function commandStarted(CommandStartedEvent $event): void
     {
         $command = $event->getCommand();
@@ -41,9 +37,7 @@ public function commandStarted(CommandStartedEvent $event): void
         $this->failPointsAndServers[] = [$command->configureFailPoint, $event->getServer()];
     }
 
-    /**
-     * @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php
-     */
+    /** @see https://php.net/manual/en/mongodb-driver-monitoring-commandsubscriber.commandsucceeded.php */
     public function commandSucceeded(CommandSucceededEvent $event): void
     {
     }
diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php
index 9972905b4..8ed1849de 100644
--- a/tests/UnifiedSpecTests/UnifiedSpecTest.php
+++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php
@@ -88,9 +88,7 @@ public function setUp(): void
         }
     }
 
-    /**
-     * @dataProvider provideChangeStreamsTests
-     */
+    /** @dataProvider provideChangeStreamsTests */
     public function testChangeStreams(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -115,9 +113,7 @@ public function provideClientSideEncryptionTests()
         return $this->provideTests(__DIR__ . '/client-side-encryption/*.json');
     }
 
-    /**
-     * @dataProvider provideCollectionManagementTests
-     */
+    /** @dataProvider provideCollectionManagementTests */
     public function testCollectionManagement(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -128,9 +124,7 @@ public function provideCollectionManagementTests()
         return $this->provideTests(__DIR__ . '/collection-management/*.json');
     }
 
-    /**
-     * @dataProvider provideCommandMonitoringTests
-     */
+    /** @dataProvider provideCommandMonitoringTests */
     public function testCommandMonitoring(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -141,9 +135,7 @@ public function provideCommandMonitoringTests()
         return $this->provideTests(__DIR__ . '/command-monitoring/*.json');
     }
 
-    /**
-     * @dataProvider provideCrudTests
-     */
+    /** @dataProvider provideCrudTests */
     public function testCrud(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -154,9 +146,7 @@ public function provideCrudTests()
         return $this->provideTests(__DIR__ . '/crud/*.json');
     }
 
-    /**
-     * @dataProvider provideGridFSTests
-     */
+    /** @dataProvider provideGridFSTests */
     public function testGridFS(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -167,9 +157,7 @@ public function provideGridFSTests()
         return $this->provideTests(__DIR__ . '/gridfs/*.json');
     }
 
-    /**
-     * @dataProvider provideLoadBalancers
-     */
+    /** @dataProvider provideLoadBalancers */
     public function testLoadBalancers(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -180,9 +168,7 @@ public function provideLoadBalancers()
         return $this->provideTests(__DIR__ . '/load-balancers/*.json');
     }
 
-    /**
-     * @dataProvider provideSessionsTests
-     */
+    /** @dataProvider provideSessionsTests */
     public function testSessions(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -193,9 +179,7 @@ public function provideSessionsTests()
         return $this->provideTests(__DIR__ . '/sessions/*.json');
     }
 
-    /**
-     * @dataProvider provideTransactionsTests
-     */
+    /** @dataProvider provideTransactionsTests */
     public function testTransactions(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -220,9 +204,7 @@ public function provideVersionedApiTests()
         return $this->provideTests(__DIR__ . '/versioned-api/*.json');
     }
 
-    /**
-     * @dataProvider providePassingTests
-     */
+    /** @dataProvider providePassingTests */
     public function testPassingTests(UnifiedTestCase $test): void
     {
         self::$runner->run($test);
@@ -233,9 +215,7 @@ public function providePassingTests()
         yield from $this->provideTests(__DIR__ . '/valid-pass/*.json');
     }
 
-    /**
-     * @dataProvider provideFailingTests
-     */
+    /** @dataProvider provideFailingTests */
     public function testFailingTests(UnifiedTestCase $test): void
     {
         // Cannot use expectException(), as it ignores PHPUnit Exceptions

From b704462a1ede3e734106fe37412ff4ce9fb446f5 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Mon, 17 Apr 2023 22:06:36 +0800
Subject: [PATCH 275/321] PHPLIB-1088: Skip Queryable Encryption tests in QEv1
 driver for QEv2 server (#1062)

Synced with mongodb/specifications@baf3724155500acbb557e158b8a5d4334e7f3512 but omits newer range index tests, which don't apply.

* Skip QEv1 prose tests on newer server versions

* Update PHPC versions in CI matrices

Versions were from "stable" to "master" in bf85cb98f2a1474521da2d84db95048590ba811c and never reverted after PHPC's 1.14.0 release.
---
 .evergreen/config.yml                         |  16 +-
 .github/workflows/tests.yml                   |  12 +-
 tests/DocumentationExamplesTest.php           |   5 +
 .../ClientSideEncryptionSpecTest.php          |   5 +
 .../tests/fle2-BypassQueryAnalysis.json       |   4 +-
 .../tests/fle2-Compact.json                   |   4 +-
 .../tests/fle2-CreateCollection.json          | 256 +++++++++---------
 .../tests/fle2-DecryptExistingData.json       |   4 +-
 .../tests/fle2-Delete.json                    |   4 +-
 ...EncryptedFields-vs-EncryptedFieldsMap.json |  10 +-
 .../fle2-EncryptedFields-vs-jsonSchema.json   |   4 +-
 .../fle2-EncryptedFieldsMap-defaults.json     |   4 +-
 .../tests/fle2-FindOneAndUpdate.json          |   4 +-
 .../tests/fle2-InsertFind-Indexed.json        |   4 +-
 .../tests/fle2-InsertFind-Unindexed.json      |   6 +-
 .../tests/fle2-MissingKey.json                |   4 +-
 .../tests/fle2-NoEncryption.json              |   4 +-
 .../tests/fle2-Update.json                    |   4 +-
 ...e2-validatorAndPartialFieldExpression.json |   4 +-
 .../tests/maxWireVersion.json                 |   2 +-
 20 files changed, 197 insertions(+), 163 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index cd21e97c7..0ef7f6e76 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -624,22 +624,16 @@ axes:
   - id: driver-versions
     display_name: Driver Version
     values:
-      # TODO: Update to "1.14.0" once PHPC 1.14.0 is released
       - id: "oldest-supported"
-        # display_name: "1.14.0"
-        display_name: "PHPC 1.14-dev (master)"
+        display_name: "PHPC 1.14.0"
         variables:
-          # EXTENSION_VERSION: "1.14.0"
-          EXTENSION_BRANCH: "master"
-      # TODO: Update to "1.14.x"/"stable" once PHPC 1.14.0 is released
+          EXTENSION_VERSION: "1.14.0"
       - id: "latest-stable"
-        # display_name: "1.14.x"
-        display_name: "PHPC 1.14-dev (master)"
+        display_name: "PHPC (stable)"
         variables:
-          # EXTENSION_VERSION: "stable"
-          EXTENSION_BRANCH: "master"
+          EXTENSION_VERSION: "stable"
       - id: "latest-dev"
-        display_name: "PHPC 1.14-dev (master)"
+        display_name: "PHPC (master)"
         variables:
           EXTENSION_BRANCH: "master"
 
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 293862ccd..dec2067ba 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -27,34 +27,34 @@ jobs:
         mongodb-version:
           - "4.4"
         driver-version:
-          - "mongodb/mongo-php-driver@master"
+          - "stable"
         topology:
           - "server"
         include:
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "6.0"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "replica_set"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "6.0"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "sharded_cluster"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "5.0"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "server"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "4.4"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "replica_set"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "4.4"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "sharded_cluster"
 
     steps:
diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index 23ac8b50f..9745d19d4 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -1867,6 +1867,11 @@ public function testQueryableEncryption(): void
             $this->markTestSkipped('Queryable encryption requires MongoDB 6.0 or later');
         }
 
+        // Note: this version requirement is consistent with QEv1 spec tests
+        if (version_compare($this->getServerVersion(), '6.2.99', '>')) {
+            $this->markTestSkipped('MongoDB 7.0 and later requires Queryable Encryption v2 protocol');
+        }
+
         if (! $this->isEnterprise()) {
             $this->markTestSkipped('Automatic encryption requires MongoDB Enterprise');
         }
diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index 0474644e0..75f4f1087 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -1238,6 +1238,11 @@ public function testExplicitEncryption(Closure $test): void
             $this->markTestSkipped('Explicit encryption tests require MongoDB 6.0 or later');
         }
 
+        // Note: this version requirement is consistent with QEv1 spec tests
+        if (version_compare($this->getServerVersion(), '6.2.99', '>')) {
+            $this->markTestSkipped('MongoDB 7.0 and later requires Queryable Encryption v2 protocol');
+        }
+
         // Test setup
         $encryptedFields = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/encryptedFields.json'));
         $key1Document = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/keys/key1-document.json'));
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json b/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json
index 629faf189..4272e16a8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json b/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json
index 46da99cbf..b13e91b1e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
index 6836f40e0..19bd54e0d 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
@@ -20,9 +22,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -59,7 +61,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -67,7 +69,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -75,7 +77,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -100,7 +102,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -109,7 +111,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -118,7 +120,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -136,7 +138,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -151,7 +153,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -166,7 +168,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -183,9 +185,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -744,9 +746,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -761,9 +763,9 @@
               ]
             },
             "default.encryptedCollection.esc": {
-              "escCollection": "encryptedCollection",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -800,7 +802,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -808,7 +810,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -816,7 +818,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -841,7 +843,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -850,7 +852,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -859,7 +861,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -877,7 +879,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -892,7 +894,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -907,7 +909,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -924,9 +926,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -973,9 +975,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1058,9 +1060,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1097,7 +1099,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1105,7 +1107,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1113,7 +1115,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1138,7 +1140,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1147,7 +1149,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1156,7 +1158,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1174,7 +1176,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1189,7 +1191,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1204,7 +1206,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1221,9 +1223,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -1277,9 +1279,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1301,9 +1303,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1324,7 +1326,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1332,7 +1334,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1340,7 +1342,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1365,7 +1367,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1374,7 +1376,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1383,7 +1385,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1401,7 +1403,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1416,7 +1418,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1431,7 +1433,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1448,9 +1450,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -1509,9 +1511,9 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1541,7 +1543,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1550,7 +1552,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1559,7 +1561,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1593,9 +1595,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1617,9 +1619,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1640,7 +1642,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1648,7 +1650,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1656,7 +1658,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1682,9 +1684,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1705,7 +1707,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1713,7 +1715,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1721,7 +1723,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -1737,7 +1739,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1746,7 +1748,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1755,7 +1757,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1773,7 +1775,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1788,7 +1790,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1803,7 +1805,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -1820,9 +1822,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -1873,7 +1875,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1882,7 +1884,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1891,7 +1893,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -1925,9 +1927,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1949,9 +1951,9 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "encryptedCollection.esc",
-              "eccCollection": "encryptedCollection.ecc",
-              "ecocCollection": "encryptedCollection.ecoc",
+              "escCollection": "enxcol_.encryptedCollection.esc",
+              "eccCollection": "enxcol_.encryptedCollection.ecc",
+              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1972,7 +1974,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -1980,7 +1982,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -1988,7 +1990,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -2020,7 +2022,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.esc"
+            "collection": "enxcol_.encryptedCollection.esc"
           }
         },
         {
@@ -2028,7 +2030,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecc"
+            "collection": "enxcol_.encryptedCollection.ecc"
           }
         },
         {
@@ -2036,7 +2038,7 @@
           "object": "testRunner",
           "arguments": {
             "database": "default",
-            "collection": "encryptedCollection.ecoc"
+            "collection": "enxcol_.encryptedCollection.ecoc"
           }
         },
         {
@@ -2052,7 +2054,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2061,7 +2063,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2070,7 +2072,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2088,7 +2090,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.esc",
+              "create": "enxcol_.encryptedCollection.esc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -2103,7 +2105,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecc",
+              "create": "enxcol_.encryptedCollection.ecc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -2118,7 +2120,7 @@
         {
           "command_started_event": {
             "command": {
-              "create": "encryptedCollection.ecoc",
+              "create": "enxcol_.encryptedCollection.ecoc",
               "clusteredIndex": {
                 "key": {
                   "_id": 1
@@ -2135,9 +2137,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "encryptedCollection.esc",
-                "eccCollection": "encryptedCollection.ecc",
-                "ecocCollection": "encryptedCollection.ecoc",
+                "escCollection": "enxcol_.encryptedCollection.esc",
+                "eccCollection": "enxcol_.encryptedCollection.ecc",
+                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                 "fields": [
                   {
                     "path": "firstName",
@@ -2200,7 +2202,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.esc"
+              "drop": "enxcol_.encryptedCollection.esc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2209,7 +2211,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2218,7 +2220,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "encryptedCollection.ecoc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json b/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json
index c6d0bca0d..23cdab93e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json
index 0e3e06396..8e04dc5d8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
index ea3eb4850..c44bf9d2e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
@@ -93,9 +95,9 @@
           },
           "encryptedFieldsMap": {
             "default.default": {
-              "escCollection": "esc",
-              "eccCollection": "ecc",
-              "ecocCollection": "ecoc",
+              "escCollection": "enxcol_.default.esc",
+              "eccCollection": "enxcol_.default.ecc",
+              "ecocCollection": "enxcol_.default.ecoc",
               "fields": []
             }
           }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json
index 1d3227ee7..0e56912e3 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json
index 030952e05..4e13934b7 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json
index b31438876..e929c823a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json
index 81a549590..53857cac1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json
index 1a7509590..b2a3bd9d9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
@@ -241,7 +243,7 @@
             }
           },
           "result": {
-            "errorContains": "Cannot query"
+            "errorContains": "encrypt"
           }
         }
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json b/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json
index 2db1cd770..ce5c1677f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json b/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json
index e9dd586c2..39ffcf17f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json
index 87830af32..581cebbc7 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-Update.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json
index fab36f75a..286fbb6b0 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json
@@ -1,10 +1,12 @@
 {
   "runOn": [
     {
+      "maxServerVersion": "6.2.99",
       "minServerVersion": "6.0.0",
       "topology": [
         "replicaset",
-        "sharded"
+        "sharded",
+        "load-balanced"
       ]
     }
   ],
diff --git a/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json b/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json
index c1088a0ec..f04f58dff 100644
--- a/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json
+++ b/tests/SpecTests/client-side-encryption/tests/maxWireVersion.json
@@ -1,7 +1,7 @@
 {
   "runOn": [
     {
-      "maxServerVersion": "4.0"
+      "maxServerVersion": "4.0.99"
     }
   ],
   "database_name": "default",

From 621ed0ac198855eae3fb5b5d168a651e0e6bf476 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 18 Apr 2023 09:45:29 +0800
Subject: [PATCH 276/321] PHPLIB-1088: Update Queryable Encryption tests for
 QEv2 (#1063)

Following PHPC-2203, ext-mongodb 1.16-dev now uses the QEv2 protocol, which requires MongoDB 7.0+.

Serverless does not yet support QEv2, but that should be covered by the existing server version check.

Spec tests synced with mongodb/specifications@64deb2837a2355f6002775c49b9b6c50c9dc560f

Note: QEv2 spec tests are still skipped pending PHPLIB-878
---
 tests/DocumentationExamplesTest.php           |   4 +-
 ...rose21_AutomaticDataEncryptionKeysTest.php |   4 +-
 .../ClientSideEncryptionSpecTest.php          | 396 +++++++++---------
 ...s.json => fle2v2-BypassQueryAnalysis.json} |  74 +---
 ...{fle2-Compact.json => fle2v2-Compact.json} |   3 +-
 ...tion.json => fle2v2-CreateCollection.json} |   3 +-
 ...a.json => fle2v2-DecryptExistingData.json} |   3 +-
 .../{fle2-Delete.json => fle2v2-Delete.json}  |  23 +-
 ...ncryptedFields-vs-EncryptedFieldsMap.json} |   3 +-
 ...fle2v2-EncryptedFields-vs-jsonSchema.json} |   5 +-
 ...> fle2v2-EncryptedFieldsMap-defaults.json} |   4 +-
 ...date.json => fle2v2-FindOneAndUpdate.json} |  43 +-
 ...ed.json => fle2v2-InsertFind-Indexed.json} |   5 +-
 ....json => fle2v2-InsertFind-Unindexed.json} |   3 +-
 ...MissingKey.json => fle2v2-MissingKey.json} |   3 +-
 ...cryption.json => fle2v2-NoEncryption.json} |   3 +-
 ....json => fle2v2-Range-Date-Aggregate.json} |   5 +-
 ...son => fle2v2-Range-Date-Correctness.json} |   3 +-
 ...ete.json => fle2v2-Range-Date-Delete.json} |  23 +-
 ...> fle2v2-Range-Date-FindOneAndUpdate.json} |  23 +-
 ...json => fle2v2-Range-Date-InsertFind.json} |   5 +-
 ...ate.json => fle2v2-Range-Date-Update.json} |  23 +-
 ...on => fle2v2-Range-Decimal-Aggregate.json} |   5 +-
 ... => fle2v2-Range-Decimal-Correctness.json} |   3 +-
 ....json => fle2v2-Range-Decimal-Delete.json} |  23 +-
 ...le2v2-Range-Decimal-FindOneAndUpdate.json} |  23 +-
 ...n => fle2v2-Range-Decimal-InsertFind.json} |   5 +-
 ....json => fle2v2-Range-Decimal-Update.json} |  23 +-
 ...2v2-Range-DecimalPrecision-Aggregate.json} |   5 +-
 ...2-Range-DecimalPrecision-Correctness.json} |   3 +-
 ...fle2v2-Range-DecimalPrecision-Delete.json} |  23 +-
 ...ge-DecimalPrecision-FindOneAndUpdate.json} |  23 +-
 ...v2-Range-DecimalPrecision-InsertFind.json} |   5 +-
 ...fle2v2-Range-DecimalPrecision-Update.json} |  23 +-
 ...son => fle2v2-Range-Double-Aggregate.json} |   5 +-
 ...n => fle2v2-Range-Double-Correctness.json} |   3 +-
 ...e.json => fle2v2-Range-Double-Delete.json} |  23 +-
 ...fle2v2-Range-Double-FindOneAndUpdate.json} |  23 +-
 ...on => fle2v2-Range-Double-InsertFind.json} |   5 +-
 ...e.json => fle2v2-Range-Double-Update.json} |  23 +-
 ...e2v2-Range-DoublePrecision-Aggregate.json} |   5 +-
 ...v2-Range-DoublePrecision-Correctness.json} |   3 +-
 ... fle2v2-Range-DoublePrecision-Delete.json} |  23 +-
 ...nge-DoublePrecision-FindOneAndUpdate.json} |  23 +-
 ...2v2-Range-DoublePrecision-InsertFind.json} |   5 +-
 ... fle2v2-Range-DoublePrecision-Update.json} |  23 +-
 ...e.json => fle2v2-Range-Int-Aggregate.json} |   5 +-
 ...json => fle2v2-Range-Int-Correctness.json} |   3 +-
 ...lete.json => fle2v2-Range-Int-Delete.json} |  23 +-
 ...=> fle2v2-Range-Int-FindOneAndUpdate.json} |  23 +-
 ....json => fle2v2-Range-Int-InsertFind.json} |   5 +-
 ...date.json => fle2v2-Range-Int-Update.json} |  23 +-
 ....json => fle2v2-Range-Long-Aggregate.json} |   5 +-
 ...son => fle2v2-Range-Long-Correctness.json} |   3 +-
 ...ete.json => fle2v2-Range-Long-Delete.json} |  23 +-
 ...> fle2v2-Range-Long-FindOneAndUpdate.json} |  23 +-
 ...json => fle2v2-Range-Long-InsertFind.json} |   5 +-
 ...ate.json => fle2v2-Range-Long-Update.json} |  23 +-
 ...gType.json => fle2v2-Range-WrongType.json} |   3 +-
 .../{fle2-Update.json => fle2v2-Update.json}  |  43 +-
 ...2-validatorAndPartialFieldExpression.json} |   3 +-
 61 files changed, 364 insertions(+), 838 deletions(-)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-BypassQueryAnalysis.json => fle2v2-BypassQueryAnalysis.json} (64%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Compact.json => fle2v2-Compact.json} (98%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-CreateCollection.json => fle2v2-CreateCollection.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-DecryptExistingData.json => fle2v2-DecryptExistingData.json} (98%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Delete.json => fle2v2-Delete.json} (89%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-EncryptedFields-vs-EncryptedFieldsMap.json => fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json} (98%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-EncryptedFields-vs-jsonSchema.json => fle2v2-EncryptedFields-vs-jsonSchema.json} (97%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-EncryptedFieldsMap-defaults.json => fle2v2-EncryptedFieldsMap-defaults.json} (96%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-FindOneAndUpdate.json => fle2v2-FindOneAndUpdate.json} (89%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-InsertFind-Indexed.json => fle2v2-InsertFind-Indexed.json} (97%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-InsertFind-Unindexed.json => fle2v2-InsertFind-Unindexed.json} (98%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-MissingKey.json => fle2v2-MissingKey.json} (97%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-NoEncryption.json => fle2v2-NoEncryption.json} (96%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Date-Aggregate.json => fle2v2-Range-Date-Aggregate.json} (91%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Date-Correctness.json => fle2v2-Range-Date-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Date-Delete.json => fle2v2-Range-Date-Delete.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Date-FindOneAndUpdate.json => fle2v2-Range-Date-FindOneAndUpdate.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Date-InsertFind.json => fle2v2-Range-Date-InsertFind.json} (91%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Date-Update.json => fle2v2-Range-Date-Update.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Decimal-Aggregate.json => fle2v2-Range-Decimal-Aggregate.json} (76%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Decimal-Correctness.json => fle2v2-Range-Decimal-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Decimal-Delete.json => fle2v2-Range-Decimal-Delete.json} (66%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Decimal-FindOneAndUpdate.json => fle2v2-Range-Decimal-FindOneAndUpdate.json} (76%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Decimal-InsertFind.json => fle2v2-Range-Decimal-InsertFind.json} (76%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Decimal-Update.json => fle2v2-Range-Decimal-Update.json} (76%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DecimalPrecision-Aggregate.json => fle2v2-Range-DecimalPrecision-Aggregate.json} (88%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DecimalPrecision-Correctness.json => fle2v2-Range-DecimalPrecision-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DecimalPrecision-Delete.json => fle2v2-Range-DecimalPrecision-Delete.json} (82%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DecimalPrecision-FindOneAndUpdate.json => fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DecimalPrecision-InsertFind.json => fle2v2-Range-DecimalPrecision-InsertFind.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DecimalPrecision-Update.json => fle2v2-Range-DecimalPrecision-Update.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Double-Aggregate.json => fle2v2-Range-Double-Aggregate.json} (82%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Double-Correctness.json => fle2v2-Range-Double-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Double-Delete.json => fle2v2-Range-Double-Delete.json} (74%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Double-FindOneAndUpdate.json => fle2v2-Range-Double-FindOneAndUpdate.json} (81%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Double-InsertFind.json => fle2v2-Range-Double-InsertFind.json} (82%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Double-Update.json => fle2v2-Range-Double-Update.json} (81%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DoublePrecision-Aggregate.json => fle2v2-Range-DoublePrecision-Aggregate.json} (88%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DoublePrecision-Correctness.json => fle2v2-Range-DoublePrecision-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DoublePrecision-Delete.json => fle2v2-Range-DoublePrecision-Delete.json} (82%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DoublePrecision-FindOneAndUpdate.json => fle2v2-Range-DoublePrecision-FindOneAndUpdate.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DoublePrecision-InsertFind.json => fle2v2-Range-DoublePrecision-InsertFind.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-DoublePrecision-Update.json => fle2v2-Range-DoublePrecision-Update.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Int-Aggregate.json => fle2v2-Range-Int-Aggregate.json} (90%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Int-Correctness.json => fle2v2-Range-Int-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Int-Delete.json => fle2v2-Range-Int-Delete.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Int-FindOneAndUpdate.json => fle2v2-Range-Int-FindOneAndUpdate.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Int-InsertFind.json => fle2v2-Range-Int-InsertFind.json} (90%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Int-Update.json => fle2v2-Range-Int-Update.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Long-Aggregate.json => fle2v2-Range-Long-Aggregate.json} (90%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Long-Correctness.json => fle2v2-Range-Long-Correctness.json} (99%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Long-Delete.json => fle2v2-Range-Long-Delete.json} (85%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Long-FindOneAndUpdate.json => fle2v2-Range-Long-FindOneAndUpdate.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Long-InsertFind.json => fle2v2-Range-Long-InsertFind.json} (90%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-Long-Update.json => fle2v2-Range-Long-Update.json} (87%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Range-WrongType.json => fle2v2-Range-WrongType.json} (98%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-Update.json => fle2v2-Update.json} (90%)
 rename tests/SpecTests/client-side-encryption/tests/{fle2-validatorAndPartialFieldExpression.json => fle2v2-validatorAndPartialFieldExpression.json} (99%)

diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index 1c580dcde..5e0c592cf 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -1859,8 +1859,8 @@ public function testQueryableEncryption(): void
             $this->markTestSkipped('Queryable encryption requires replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '6.0.0', '<')) {
-            $this->markTestSkipped('Queryable encryption requires MongoDB 6.0 or later');
+        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
+            $this->markTestSkipped('Explicit encryption tests require MongoDB 7.0 or later');
         }
 
         if (! $this->isEnterprise()) {
diff --git a/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php b/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
index 45e70f248..91cad0e1d 100644
--- a/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
+++ b/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
@@ -35,8 +35,8 @@ public function setUp(): void
             $this->markTestSkipped('Automatic data encryption key tests require replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '6.0.0', '<')) {
-            $this->markTestSkipped('Automatic data encryption key tests require MongoDB 6.0 or later');
+        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
+            $this->markTestSkipped('Automatic data encryption key tests require MongoDB 7.0 or later');
         }
 
         $client = static::createTestClient();
diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index 87e309cc9..f63ceae3e 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -64,202 +64,202 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase
     /** @var array */
     private static $incompleteTests = [
         'explain: Explain a find with deterministic encryption' => 'crypt_shared does not add apiVersion field to explain commands (PHPLIB-947, SERVER-69564)',
-        'fle2-Range-Date-Aggregate: FLE2 Range Date. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Delete: FLE2 Range Date. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-FindOneAndUpdate: FLE2 Range Date. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-InsertFind: FLE2 Range Date. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Date-Update: FLE2 Range Date. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Aggregate: FLE2 Range Decimal. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Delete: FLE2 Range Decimal. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-FindOneAndUpdate: FLE2 Range Decimal. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-InsertFind: FLE2 Range Decimal. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Aggregate: FLE2 Range DecimalPrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Delete: FLE2 Range DecimalPrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-FindOneAndUpdate: FLE2 Range DecimalPrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-InsertFind: FLE2 Range DecimalPrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DecimalPrecision-Update: FLE2 Range DecimalPrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Decimal-Update: FLE2 Range Decimal. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Aggregate: FLE2 Range Double. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Delete: FLE2 Range Double. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-FindOneAndUpdate: FLE2 Range Double. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-InsertFind: FLE2 Range Double. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Aggregate: FLE2 Range DoublePrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Delete: FLE2 Range DoublePrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-FindOneAndUpdate: FLE2 Range DoublePrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-InsertFind: FLE2 Range DoublePrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-DoublePrecision-Update: FLE2 Range DoublePrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Double-Update: FLE2 Range Double. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Aggregate: FLE2 Range Int. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Delete: FLE2 Range Int. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-FindOneAndUpdate: FLE2 Range Int. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-InsertFind: FLE2 Range Int. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Int-Update: FLE2 Range Int. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Aggregate: FLE2 Range Long. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Delete: FLE2 Range Long. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-FindOneAndUpdate: FLE2 Range Long. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-InsertFind: FLE2 Range Long. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-Long-Update: FLE2 Range Long. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-WrongType: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2-Range-WrongType: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Aggregate: FLE2 Range Date. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Delete: FLE2 Range Date. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-FindOneAndUpdate: FLE2 Range Date. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-InsertFind: FLE2 Range Date. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Date-Update: FLE2 Range Date. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Aggregate: FLE2 Range Decimal. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Delete: FLE2 Range Decimal. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-FindOneAndUpdate: FLE2 Range Decimal. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-InsertFind: FLE2 Range Decimal. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Aggregate: FLE2 Range DecimalPrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Delete: FLE2 Range DecimalPrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-FindOneAndUpdate: FLE2 Range DecimalPrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-InsertFind: FLE2 Range DecimalPrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DecimalPrecision-Update: FLE2 Range DecimalPrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Update: FLE2 Range Decimal. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Aggregate: FLE2 Range Double. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Delete: FLE2 Range Double. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-FindOneAndUpdate: FLE2 Range Double. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-InsertFind: FLE2 Range Double. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Aggregate: FLE2 Range DoublePrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Delete: FLE2 Range DoublePrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-FindOneAndUpdate: FLE2 Range DoublePrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-InsertFind: FLE2 Range DoublePrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-DoublePrecision-Update: FLE2 Range DoublePrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Double-Update: FLE2 Range Double. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Aggregate: FLE2 Range Int. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Delete: FLE2 Range Int. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-FindOneAndUpdate: FLE2 Range Int. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-InsertFind: FLE2 Range Int. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Int-Update: FLE2 Range Int. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Aggregate: FLE2 Range Long. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Delete: FLE2 Range Long. Delete.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-FindOneAndUpdate: FLE2 Range Long. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-InsertFind: FLE2 Range Long. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Long-Update: FLE2 Range Long. Update.' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-WrongType: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-WrongType: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
         'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)',
         'timeoutMS: remaining timeoutMS applied to find to get keyvault data' => 'Not yet implemented (PHPC-1760)',
     ];
@@ -1425,8 +1425,8 @@ public function testExplicitEncryption(Closure $test): void
             $this->markTestSkipped('Explicit encryption tests require replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '6.0.0', '<')) {
-            $this->markTestSkipped('Explicit encryption tests require MongoDB 6.0 or later');
+        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
+            $this->markTestSkipped('Explicit encryption tests require MongoDB 7.0 or later');
         }
 
         // Test setup
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
similarity index 64%
rename from tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
index b8d06e8bc..8f98cd6f2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-BypassQueryAnalysis.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -75,36 +76,6 @@
       "masterKey": {
         "provider": "local"
       }
-    },
-    {
-      "_id": {
-        "$binary": {
-          "base64": "q83vqxI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "keyMaterial": {
-        "$binary": {
-          "base64": "HBk9BWihXExNDvTp1lUxOuxuZK2Pe2ZdVdlsxPEBkiO1bS4mG5NNDsQ7zVxJAH8BtdOYp72Ku4Y3nwc0BUpIKsvAKX4eYXtlhv5zUQxWdeNFhg9qK7qb8nqhnnLeT0f25jFSqzWJoT379hfwDeu0bebJHr35QrJ8myZdPMTEDYF08QYQ48ShRBli0S+QzBHHAQiM2iJNr4svg2WR8JSeWQ==",
-          "subType": "00"
-        }
-      },
-      "creationDate": {
-        "$date": {
-          "$numberLong": "1648914851981"
-        }
-      },
-      "updateDate": {
-        "$date": {
-          "$numberLong": "1648914851981"
-        }
-      },
-      "status": {
-        "$numberInt": "0"
-      },
-      "masterKey": {
-        "provider": "local"
-      }
     }
   ],
   "tests": [
@@ -133,7 +104,7 @@
               "_id": 1,
               "encryptedIndexed": {
                 "$binary": {
-                  "base64": "BHEBAAAFZAAgAAAAAHb62aV7+mqmaGcotPLdG3KP7S8diFwWMLM/5rYtqLrEBXMAIAAAAAAVJ6OWHRv3OtCozHpt3ZzfBhaxZirLv3B+G8PuaaO4EgVjACAAAAAAsZXWOWA+UiCBbrJNB6bHflB/cn7pWSvwWN2jw4FPeIUFcABQAAAAAMdD1nV2nqeI1eXEQNskDflCy8I7/HvvqDKJ6XxjhrPQWdLqjz+8GosGUsB7A8ee/uG9/guENuL25XD+Fxxkv1LLXtavHOlLF7iW0u9yabqqBXUAEAAAAAQSNFZ4EjSYdhI0EjRWeJASEHQAAgAAAAV2AE0AAAAAq83vqxI0mHYSNBI0VniQEkzZZBBDgeZh+h+gXEmOrSFtVvkUcnHWj/rfPW7iJ0G3UJ8zpuBmUM/VjOMJCY4+eDqdTiPIwX+/vNXegc8FZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsAA==",
+                  "base64": "C18BAAAFZAAgAAAAANnt+eLTkv4GdDPl8IAfJOvTzArOgFJQ2S/DcLza4W0DBXMAIAAAAAD2u+omZme3P2gBPehMQyQHQ153tPN1+z7bksYA9jKTpAVwADAAAAAAUnCOQqIvmR65YKyYnsiVfVrg9hwUVO3RhhKExo3RWOzgaS0QdsBL5xKFS0JhZSoWBXUAEAAAAAQSNFZ4EjSYdhI0EjRWeJASEHQAAgAAAAV2AFAAAAAAEjRWeBI0mHYSNBI0VniQEpQbp/ZJpWBKeDtKLiXb0P2E9wvc0g3f373jnYQYlJquOrlPOoEy3ngsHPJuSUijvWDsrQzqYa349K7G/66qaXEFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsBWwAIAAAAACkm0o9bj6j0HuADKc0svbqO2UHj6GrlNdF6yKNxh63xRJrAAAAAAAAAAAAAA==",
                   "subType": "06"
                 }
               }
@@ -150,7 +121,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedIndexed": "value123"
+              "encryptedIndexed": "123"
             }
           ]
         }
@@ -176,7 +147,7 @@
                   "_id": 1,
                   "encryptedIndexed": {
                     "$binary": {
-                      "base64": "BHEBAAAFZAAgAAAAAHb62aV7+mqmaGcotPLdG3KP7S8diFwWMLM/5rYtqLrEBXMAIAAAAAAVJ6OWHRv3OtCozHpt3ZzfBhaxZirLv3B+G8PuaaO4EgVjACAAAAAAsZXWOWA+UiCBbrJNB6bHflB/cn7pWSvwWN2jw4FPeIUFcABQAAAAAMdD1nV2nqeI1eXEQNskDflCy8I7/HvvqDKJ6XxjhrPQWdLqjz+8GosGUsB7A8ee/uG9/guENuL25XD+Fxxkv1LLXtavHOlLF7iW0u9yabqqBXUAEAAAAAQSNFZ4EjSYdhI0EjRWeJASEHQAAgAAAAV2AE0AAAAAq83vqxI0mHYSNBI0VniQEkzZZBBDgeZh+h+gXEmOrSFtVvkUcnHWj/rfPW7iJ0G3UJ8zpuBmUM/VjOMJCY4+eDqdTiPIwX+/vNXegc8FZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsAA==",
+                      "base64": "C18BAAAFZAAgAAAAANnt+eLTkv4GdDPl8IAfJOvTzArOgFJQ2S/DcLza4W0DBXMAIAAAAAD2u+omZme3P2gBPehMQyQHQ153tPN1+z7bksYA9jKTpAVwADAAAAAAUnCOQqIvmR65YKyYnsiVfVrg9hwUVO3RhhKExo3RWOzgaS0QdsBL5xKFS0JhZSoWBXUAEAAAAAQSNFZ4EjSYdhI0EjRWeJASEHQAAgAAAAV2AFAAAAAAEjRWeBI0mHYSNBI0VniQEpQbp/ZJpWBKeDtKLiXb0P2E9wvc0g3f373jnYQYlJquOrlPOoEy3ngsHPJuSUijvWDsrQzqYa349K7G/66qaXEFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsBWwAIAAAAACkm0o9bj6j0HuADKc0svbqO2UHj6GrlNdF6yKNxh63xRJrAAAAAAAAAAAAAA==",
                       "subType": "06"
                     }
                   }
@@ -230,39 +201,6 @@
             },
             "command_name": "find"
           }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "find": "datakeys",
-              "filter": {
-                "$or": [
-                  {
-                    "_id": {
-                      "$in": [
-                        {
-                          "$binary": {
-                            "base64": "q83vqxI0mHYSNBI0VniQEg==",
-                            "subType": "04"
-                          }
-                        }
-                      ]
-                    }
-                  },
-                  {
-                    "keyAltNames": {
-                      "$in": []
-                    }
-                  }
-                ]
-              },
-              "$db": "keyvault",
-              "readConcern": {
-                "level": "majority"
-              }
-            },
-            "command_name": "find"
-          }
         }
       ],
       "outcome": {
@@ -276,7 +214,7 @@
               "__safeContent__": [
                 {
                   "$binary": {
-                    "base64": "ThpoKfQ8AkOzkFfNC1+9PF0pY2nIzfXvRdxQgjkNbBw=",
+                    "base64": "31eCYlbQoVboc5zwC8IoyJVSkag9PxREka8dkmbXJeY=",
                     "subType": "00"
                   }
                 }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
similarity index 98%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Compact.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
index 6ca0f9ba0..e3d936e34 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Compact.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
index 7f4f38161..5e197848f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-CreateCollection.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json
similarity index 98%
rename from tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json
index e622d3334..905d3c945 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-DecryptExistingData.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
similarity index 89%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
index 868712774..2eb33c96e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -226,7 +227,7 @@
                     "encryptedIndexed": {
                       "$eq": {
                         "$binary": {
-                          "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                          "base64": "DIkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVsACAAAAAAaZ9s3G+4znfxStxeOZwcZy1OhzjMGc5hjmdMN+b/w6kSY20AAAAAAAAAAAAA",
                           "subType": "06"
                         }
                       }
@@ -271,24 +272,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedIndexed": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
similarity index 98%
rename from tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
index 42cd4bbc9..b4edec7e1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-EncryptedFieldsMap.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
similarity index 97%
rename from tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
index f4386483d..a9cabfa1e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFields-vs-jsonSchema.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -231,7 +232,7 @@
                 "encryptedIndexed": {
                   "$eq": {
                     "$binary": {
-                      "base64": "BbEAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                      "base64": "DIkAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVsACAAAAAApJtKPW4+o9B7gAynNLL26jtlB4+hq5TXResijcYet8USY20AAAAAAAAAAAAA",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
similarity index 96%
rename from tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
index 60820aae9..d565bdcf1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-EncryptedFieldsMap-defaults.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -75,7 +76,6 @@
                   "default.default": {
                     "fields": [],
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc"
                   }
                 }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
similarity index 89%
rename from tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
index de1b5c5aa..2124ae401 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -231,7 +232,7 @@
                 "encryptedIndexed": {
                   "$eq": {
                     "$binary": {
-                      "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                      "base64": "DIkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVsACAAAAAAaZ9s3G+4znfxStxeOZwcZy1OhzjMGc5hjmdMN+b/w6kSY20AAAAAAAAAAAAA",
                       "subType": "06"
                     }
                   }
@@ -278,24 +279,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedIndexed": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
@@ -491,7 +474,7 @@
                 "encryptedIndexed": {
                   "$eq": {
                     "$binary": {
-                      "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                      "base64": "DIkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVsACAAAAAAaZ9s3G+4znfxStxeOZwcZy1OhzjMGc5hjmdMN+b/w6kSY20AAAAAAAAAAAAA",
                       "subType": "06"
                     }
                   }
@@ -540,24 +523,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedIndexed": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
similarity index 97%
rename from tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
index 84b69d7de..e18deac43 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Indexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -227,7 +228,7 @@
                 "encryptedIndexed": {
                   "$eq": {
                     "$binary": {
-                      "base64": "BbEAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVjACAAAAAAWuidNu47c9A4Clic3DvFhn1AQJVC+FJtoE5bGZuz6PsFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                      "base64": "DIkAAAAFZAAgAAAAAPGmZcUzdE/FPILvRSyAScGvZparGI2y9rJ/vSBxgCujBXMAIAAAAACi1RjmndKqgnXy7xb22RzUbnZl1sOZRXPOC0KcJkAxmQVsACAAAAAApJtKPW4+o9B7gAynNLL26jtlB4+hq5TXResijcYet8USY20AAAAAAAAAAAAA",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
similarity index 98%
rename from tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
index 9b3143852..ef7bfbfd7 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-InsertFind-Unindexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
similarity index 97%
rename from tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
index 4210da09e..c7bbe71c4 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-MissingKey.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json
similarity index 96%
rename from tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json
index 9d255bd49..185691d61 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-NoEncryption.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
similarity index 91%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
index a35321cd3..0d4e163b2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -324,7 +325,7 @@
                     "encryptedDate": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
index 5832e8541..35d639f67 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
index b5856e762..8f7500eb9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -313,7 +314,7 @@
                     "encryptedDate": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
@@ -361,24 +362,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDate": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
index a59258a46..b9739331f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -326,7 +327,7 @@
                 "encryptedDate": {
                   "$gt": {
                     "$binary": {
-                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
@@ -378,24 +379,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDate": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
similarity index 91%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
index 4357fafee..c9dc66d94 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -318,7 +319,7 @@
                 "encryptedDate": {
                   "$gt": {
                     "$binary": {
-                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
index fd170554f..13e263331 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Date-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -326,7 +327,7 @@
                     "encryptedDate": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
@@ -380,24 +381,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDate": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
similarity index 76%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
index 73d2cf489..cff4558a5 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
@@ -284,7 +285,7 @@
                     "encryptedDecimal": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
index 89b7bd311..ff9f5a9b4 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
similarity index 66%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
index 0463be1c6..1a094b853 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
@@ -275,7 +276,7 @@
                     "encryptedDecimal": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -313,24 +314,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDecimal": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
similarity index 76%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
index d0e296777..5dc95283a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
@@ -284,7 +285,7 @@
                 "encryptedDecimal": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "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",
                       "subType": "06"
                     }
                   }
@@ -326,24 +327,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDecimal": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
similarity index 76%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
index cea03e23f..6e881332d 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
@@ -278,7 +279,7 @@
                 "encryptedDecimal": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "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",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
similarity index 76%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
index 2f8b991cf..9d2cc6995 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Decimal-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
@@ -286,7 +287,7 @@
                     "encryptedDecimal": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -330,24 +331,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDecimal": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
similarity index 88%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
index a3e605d1b..876357fa7 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -313,7 +314,7 @@
                     "encryptedDecimalPrecision": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
index 9fafc243d..d8c40a7a8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
similarity index 82%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
index 3d7d359af..c219d36e5 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -304,7 +305,7 @@
                     "encryptedDecimalPrecision": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -351,24 +352,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDecimalPrecision": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
index b1442c3a3..7a7a9218e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -313,7 +314,7 @@
                 "encryptedDecimalPrecision": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "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",
                       "subType": "06"
                     }
                   }
@@ -364,24 +365,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDecimalPrecision": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
index 3b8202ff8..5453e6c8a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -307,7 +308,7 @@
                 "encryptedDecimalPrecision": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "DdIJAAADcGF5bG9hZACiCQAABGcAjgkAAAMwAH0AAAAFZAAgAAAAAHdJ2Vnb4MMzqVYVssjSdDy8XU4GVzMTfGifGETgQ2mYBXMAIAAAAAD7cFfKJGIXo6PjyeX2ria02CckW7dWFDoY/3FyBdm1NQVsACAAAAAAhEPSNv4M023A3hzNFuy83+hIKuZ2mKRY954N++aEOBUAAzEAfQAAAAVkACAAAAAAlmvfDrZoydUet4eCVMq7z6a58Ea+1HLJOWxN5lNcrWEFcwAgAAAAAEBo5AWZyC41b9ayjWNQSL4iYEAIwR/JG+ssN8bdoK9RBWwAIAAAAACEndE0SLxFSElOrNnqeX0EPmgDio3udZjVREy4JLS3sQADMgB9AAAABWQAIAAAAABbiLaoxAA6rinMJw1hC8ZUiq6UU1AQaPFn/py/Y06WuQVzACAAAAAAhtDasFkvYE7SCNu1je/hxdE9TJtAvvH3NtdEbKzNbCUFbAAgAAAAAIGepU1RSCF8sWODHEpKglsoqw3VBBH4a/URGxgGzbq2AAMzAH0AAAAFZAAgAAAAALORWwSr+tYNxcil2KIGSbNhTHvcPbdj+rLVQNx21S/KBXMAIAAAAAD6diZBkPEJ1cQy06LAxdbNK8Nlxbb44fH4Wk3Y3260nQVsACAAAAAA1eYAZBFHlDiaDAljWi8blGQ2nvvZa5AO5doeo0SFZsgAAzQAfQAAAAVkACAAAAAAG5XMK96PjClNlUvg82j4pMY1YxsznZfj4uNweD394FoFcwAgAAAAAKHgQLdGJHkrfFg9nB93Ac+3VgBw6aU44MTkKIQ91dZoBWwAIAAAAAAPxXmi+SDJ+40A0KdwfRczexlZQrHjIA+D3oUB0EY9tAADNQB9AAAABWQAIAAAAAA6M++b9I0YFemmWBAWAE3glu2Ah3Ta1FBxAQEIWS0toAVzACAAAAAANXYTqPf1Y6X3Ns6YQIX0C3FKCyWUo+Kk+fNcQvc0WSoFbAAgAAAAAA+uJUw1ICYgyeygSRe206VTWVtUnhdci3iHbyP5YtEVAAM2AH0AAAAFZAAgAAAAAKl8bV1riH/uyJ+X0HHd3+18k2cJl2dQFXCdoagutFcaBXMAIAAAAABm8F2Ew9f0VOABdcF+lP0Bi+zWvEUPniWgrxPq/Sx3uwVsACAAAAAAJfFErjZ6BPhsw5LjJLqNtKDLJ4zV0eIZppQpd9b0wZoAAzcAfQAAAAVkACAAAAAAsYZD8JEP6kYsPncFnNZwJxhu4YtUTKPNcjHtv67H+rYFcwAgAAAAAI4LqZcRkvbs/2F62Flu0pixNcor4WmBD0DHGaf039wLBWwAIAAAAAD4wUR3xd9lKltcqqo8LYvdMQWzCRobkV/ppKB/yn5dUgADOAB9AAAABWQAIAAAAAC0vdAi+dmoIXvZ5LqUqvyKV9/tHqSI2SWiSJO5pTnA2wVzACAAAAAAS2qvf9fvfVUH5WtsVxjxmskpGjYTQV34LwvQQw1y9wIFbAAgAAAAAE0+FKuK7HxbypvCeEJzMTcjOWE0ScYOlTBMUNlIv55hAAM5AH0AAAAFZAAgAAAAAH31lb/srBcrOXkzddCwAnclsR5/3QijEVgECs2JjOWBBXMAIAAAAABg7+prDT73YcCvLE5QbuIrqGcjLc5pQD2Miq0d29yrxgVsACAAAAAAetRiPwDSFWBzpWSWkOKWM6fKStRJ8SyObnpc79ux8p0AAzEwAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzExAH0AAAAFZAAgAAAAAFdthRhe2Q8CvxGIhjTJZv0Lk97GkHciTPxZ/mckLoNaBXMAIAAAAAAqOxsAr23LOVB0DIHbPf9UDJJRFXY2YoKbjhRqw5psbQVsACAAAAAA0G2GD8ZQjDBntjLpW4rqwKRS6HiUjL03g1N6chANozcAAzEyAH0AAAAFZAAgAAAAAMWymwwbvIeMqmnKWWifUqoCxOsdpnonM2qdLPyjqJO/BXMAIAAAAAB6IDmmpUhBD2zpRj8/y/kmOSXcjuIU14sNh6GKSsg2uwVsACAAAAAAWMFPNOk3EMSQDS9JGPSMIQP0oNGVugxXKKUrIPPlhHgAAzEzAH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzE0AH0AAAAFZAAgAAAAAJaRYmo8zqI2BEUzdSwp4tVRpPmVWsfydkYN3UHh6TMuBXMAIAAAAAAeD6mDnQeLlbC9i0sVgE8+RH6y+e94OJQ0tJ0PvblVSgVsACAAAAAAWp4jvretbDEsqEMzP/WLTnwOiJwCtfrCiB6m8k+yEMoAAzE1AH0AAAAFZAAgAAAAAAZZ538coNPwyRjhEwr5P8Xw32oWOJF+R+nfCGgy2qO3BXMAIAAAAACOPLnJlKwGNPDBReRKnHfteq0wFb3ezhrc7BVXs8RUHwVsACAAAAAA+lGesNk3+SyB/60rSvdQ2aN2vfJPR7llJVhufGTNhHkAAzE2AH0AAAAFZAAgAAAAAFH9l9GGA1I52atJV5jNUf1lx8jBjoEoVoME97v5GFJiBXMAIAAAAAC1qH3Kd78Dr9NGbw7y9D/XYBwv5h1LLO8la5OU7g8UkQVsACAAAAAArZ6atJCYrVfHB8dSNPOFf6nnDADBMJcIEj8ljPvxHp8AAzE3AH0AAAAFZAAgAAAAADtbVEI2tdkrowEMdkacD2w0Y3T3Ofi7PH6HmA6sP0c/BXMAIAAAAADuBSROnZHA+NgUPH8d0LnWFiDsM2bY8bzjC1+elSsIygVsACAAAAAAR0G2m+uANoWknkr/NerFcG+fECVxNIs0cqbY1t/U/0MAAzE4AH0AAAAFZAAgAAAAAAh3WpeMVlikPFYj9hLj+fmIqVt6omCSF75W3TPExyWpBXMAIAAAAAAsQkRmwqeVj2gGE03orb6PtrIzDt6dDU3hgSQi8E2wKgVsACAAAAAA3GHaRE2RAcaBRd8VzmYzWeBD2Gmy91eTK1k8YdWObZcAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
index 3dc6631c6..fa94097ef 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DecimalPrecision-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -315,7 +316,7 @@
                     "encryptedDecimalPrecision": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -368,24 +369,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDecimalPrecision": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
similarity index 82%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
index 3d54be3d1..d6118bfa1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -286,7 +287,7 @@
                     "encryptedDouble": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
index b09e96632..e455c72dc 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
similarity index 74%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
index fa09cb87d..05a78d614 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -277,7 +278,7 @@
                     "encryptedDouble": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -315,24 +316,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDouble": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
similarity index 81%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
index 59a304166..6712f7920 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -286,7 +287,7 @@
                 "encryptedDouble": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "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",
                       "subType": "06"
                     }
                   }
@@ -328,24 +329,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDouble": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
similarity index 82%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
index 634230eac..a9d9bed7c 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -280,7 +281,7 @@
                 "encryptedDouble": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "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",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
similarity index 81%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
index cdc9f28e7..91387dd90 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Double-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -288,7 +289,7 @@
                     "encryptedDouble": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -332,24 +333,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDouble": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
similarity index 88%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
index f2ea49ad7..a6fd2c164 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -313,7 +314,7 @@
                     "encryptedDoublePrecision": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "DdIJAAADcGF5bG9hZACiCQAABGcAjgkAAAMwAH0AAAAFZAAgAAAAAHdJ2Vnb4MMzqVYVssjSdDy8XU4GVzMTfGifGETgQ2mYBXMAIAAAAAD7cFfKJGIXo6PjyeX2ria02CckW7dWFDoY/3FyBdm1NQVsACAAAAAAhEPSNv4M023A3hzNFuy83+hIKuZ2mKRY954N++aEOBUAAzEAfQAAAAVkACAAAAAAlmvfDrZoydUet4eCVMq7z6a58Ea+1HLJOWxN5lNcrWEFcwAgAAAAAEBo5AWZyC41b9ayjWNQSL4iYEAIwR/JG+ssN8bdoK9RBWwAIAAAAACEndE0SLxFSElOrNnqeX0EPmgDio3udZjVREy4JLS3sQADMgB9AAAABWQAIAAAAABbiLaoxAA6rinMJw1hC8ZUiq6UU1AQaPFn/py/Y06WuQVzACAAAAAAhtDasFkvYE7SCNu1je/hxdE9TJtAvvH3NtdEbKzNbCUFbAAgAAAAAIGepU1RSCF8sWODHEpKglsoqw3VBBH4a/URGxgGzbq2AAMzAH0AAAAFZAAgAAAAALORWwSr+tYNxcil2KIGSbNhTHvcPbdj+rLVQNx21S/KBXMAIAAAAAD6diZBkPEJ1cQy06LAxdbNK8Nlxbb44fH4Wk3Y3260nQVsACAAAAAA1eYAZBFHlDiaDAljWi8blGQ2nvvZa5AO5doeo0SFZsgAAzQAfQAAAAVkACAAAAAAG5XMK96PjClNlUvg82j4pMY1YxsznZfj4uNweD394FoFcwAgAAAAAKHgQLdGJHkrfFg9nB93Ac+3VgBw6aU44MTkKIQ91dZoBWwAIAAAAAAPxXmi+SDJ+40A0KdwfRczexlZQrHjIA+D3oUB0EY9tAADNQB9AAAABWQAIAAAAAA6M++b9I0YFemmWBAWAE3glu2Ah3Ta1FBxAQEIWS0toAVzACAAAAAANXYTqPf1Y6X3Ns6YQIX0C3FKCyWUo+Kk+fNcQvc0WSoFbAAgAAAAAA+uJUw1ICYgyeygSRe206VTWVtUnhdci3iHbyP5YtEVAAM2AH0AAAAFZAAgAAAAAKl8bV1riH/uyJ+X0HHd3+18k2cJl2dQFXCdoagutFcaBXMAIAAAAABm8F2Ew9f0VOABdcF+lP0Bi+zWvEUPniWgrxPq/Sx3uwVsACAAAAAAJfFErjZ6BPhsw5LjJLqNtKDLJ4zV0eIZppQpd9b0wZoAAzcAfQAAAAVkACAAAAAAsYZD8JEP6kYsPncFnNZwJxhu4YtUTKPNcjHtv67H+rYFcwAgAAAAAI4LqZcRkvbs/2F62Flu0pixNcor4WmBD0DHGaf039wLBWwAIAAAAAD4wUR3xd9lKltcqqo8LYvdMQWzCRobkV/ppKB/yn5dUgADOAB9AAAABWQAIAAAAAC0vdAi+dmoIXvZ5LqUqvyKV9/tHqSI2SWiSJO5pTnA2wVzACAAAAAAS2qvf9fvfVUH5WtsVxjxmskpGjYTQV34LwvQQw1y9wIFbAAgAAAAAE0+FKuK7HxbypvCeEJzMTcjOWE0ScYOlTBMUNlIv55hAAM5AH0AAAAFZAAgAAAAAH31lb/srBcrOXkzddCwAnclsR5/3QijEVgECs2JjOWBBXMAIAAAAABg7+prDT73YcCvLE5QbuIrqGcjLc5pQD2Miq0d29yrxgVsACAAAAAAetRiPwDSFWBzpWSWkOKWM6fKStRJ8SyObnpc79ux8p0AAzEwAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzExAH0AAAAFZAAgAAAAAFdthRhe2Q8CvxGIhjTJZv0Lk97GkHciTPxZ/mckLoNaBXMAIAAAAAAqOxsAr23LOVB0DIHbPf9UDJJRFXY2YoKbjhRqw5psbQVsACAAAAAA0G2GD8ZQjDBntjLpW4rqwKRS6HiUjL03g1N6chANozcAAzEyAH0AAAAFZAAgAAAAAMWymwwbvIeMqmnKWWifUqoCxOsdpnonM2qdLPyjqJO/BXMAIAAAAAB6IDmmpUhBD2zpRj8/y/kmOSXcjuIU14sNh6GKSsg2uwVsACAAAAAAWMFPNOk3EMSQDS9JGPSMIQP0oNGVugxXKKUrIPPlhHgAAzEzAH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzE0AH0AAAAFZAAgAAAAAJaRYmo8zqI2BEUzdSwp4tVRpPmVWsfydkYN3UHh6TMuBXMAIAAAAAAeD6mDnQeLlbC9i0sVgE8+RH6y+e94OJQ0tJ0PvblVSgVsACAAAAAAWp4jvretbDEsqEMzP/WLTnwOiJwCtfrCiB6m8k+yEMoAAzE1AH0AAAAFZAAgAAAAAAZZ538coNPwyRjhEwr5P8Xw32oWOJF+R+nfCGgy2qO3BXMAIAAAAACOPLnJlKwGNPDBReRKnHfteq0wFb3ezhrc7BVXs8RUHwVsACAAAAAA+lGesNk3+SyB/60rSvdQ2aN2vfJPR7llJVhufGTNhHkAAzE2AH0AAAAFZAAgAAAAAFH9l9GGA1I52atJV5jNUf1lx8jBjoEoVoME97v5GFJiBXMAIAAAAAC1qH3Kd78Dr9NGbw7y9D/XYBwv5h1LLO8la5OU7g8UkQVsACAAAAAArZ6atJCYrVfHB8dSNPOFf6nnDADBMJcIEj8ljPvxHp8AAzE3AH0AAAAFZAAgAAAAADtbVEI2tdkrowEMdkacD2w0Y3T3Ofi7PH6HmA6sP0c/BXMAIAAAAADuBSROnZHA+NgUPH8d0LnWFiDsM2bY8bzjC1+elSsIygVsACAAAAAAR0G2m+uANoWknkr/NerFcG+fECVxNIs0cqbY1t/U/0MAAzE4AH0AAAAFZAAgAAAAAAh3WpeMVlikPFYj9hLj+fmIqVt6omCSF75W3TPExyWpBXMAIAAAAAAsQkRmwqeVj2gGE03orb6PtrIzDt6dDU3hgSQi8E2wKgVsACAAAAAA3GHaRE2RAcaBRd8VzmYzWeBD2Gmy91eTK1k8YdWObZcAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
index e69d91269..00f2754d2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
similarity index 82%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
index d6a9c4b7e..88c2820a2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -304,7 +305,7 @@
                     "encryptedDoublePrecision": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -351,24 +352,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDoublePrecision": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
index 0511c2e37..0186f6fd5 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -313,7 +314,7 @@
                 "encryptedDoublePrecision": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "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",
                       "subType": "06"
                     }
                   }
@@ -364,24 +365,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDoublePrecision": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
index 616101b4d..b7ce04c7c 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -307,7 +308,7 @@
                 "encryptedDoublePrecision": {
                   "$gt": {
                     "$binary": {
-                      "base64": "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",
+                      "base64": "DdIJAAADcGF5bG9hZACiCQAABGcAjgkAAAMwAH0AAAAFZAAgAAAAAHdJ2Vnb4MMzqVYVssjSdDy8XU4GVzMTfGifGETgQ2mYBXMAIAAAAAD7cFfKJGIXo6PjyeX2ria02CckW7dWFDoY/3FyBdm1NQVsACAAAAAAhEPSNv4M023A3hzNFuy83+hIKuZ2mKRY954N++aEOBUAAzEAfQAAAAVkACAAAAAAlmvfDrZoydUet4eCVMq7z6a58Ea+1HLJOWxN5lNcrWEFcwAgAAAAAEBo5AWZyC41b9ayjWNQSL4iYEAIwR/JG+ssN8bdoK9RBWwAIAAAAACEndE0SLxFSElOrNnqeX0EPmgDio3udZjVREy4JLS3sQADMgB9AAAABWQAIAAAAABbiLaoxAA6rinMJw1hC8ZUiq6UU1AQaPFn/py/Y06WuQVzACAAAAAAhtDasFkvYE7SCNu1je/hxdE9TJtAvvH3NtdEbKzNbCUFbAAgAAAAAIGepU1RSCF8sWODHEpKglsoqw3VBBH4a/URGxgGzbq2AAMzAH0AAAAFZAAgAAAAALORWwSr+tYNxcil2KIGSbNhTHvcPbdj+rLVQNx21S/KBXMAIAAAAAD6diZBkPEJ1cQy06LAxdbNK8Nlxbb44fH4Wk3Y3260nQVsACAAAAAA1eYAZBFHlDiaDAljWi8blGQ2nvvZa5AO5doeo0SFZsgAAzQAfQAAAAVkACAAAAAAG5XMK96PjClNlUvg82j4pMY1YxsznZfj4uNweD394FoFcwAgAAAAAKHgQLdGJHkrfFg9nB93Ac+3VgBw6aU44MTkKIQ91dZoBWwAIAAAAAAPxXmi+SDJ+40A0KdwfRczexlZQrHjIA+D3oUB0EY9tAADNQB9AAAABWQAIAAAAAA6M++b9I0YFemmWBAWAE3glu2Ah3Ta1FBxAQEIWS0toAVzACAAAAAANXYTqPf1Y6X3Ns6YQIX0C3FKCyWUo+Kk+fNcQvc0WSoFbAAgAAAAAA+uJUw1ICYgyeygSRe206VTWVtUnhdci3iHbyP5YtEVAAM2AH0AAAAFZAAgAAAAAKl8bV1riH/uyJ+X0HHd3+18k2cJl2dQFXCdoagutFcaBXMAIAAAAABm8F2Ew9f0VOABdcF+lP0Bi+zWvEUPniWgrxPq/Sx3uwVsACAAAAAAJfFErjZ6BPhsw5LjJLqNtKDLJ4zV0eIZppQpd9b0wZoAAzcAfQAAAAVkACAAAAAAsYZD8JEP6kYsPncFnNZwJxhu4YtUTKPNcjHtv67H+rYFcwAgAAAAAI4LqZcRkvbs/2F62Flu0pixNcor4WmBD0DHGaf039wLBWwAIAAAAAD4wUR3xd9lKltcqqo8LYvdMQWzCRobkV/ppKB/yn5dUgADOAB9AAAABWQAIAAAAAC0vdAi+dmoIXvZ5LqUqvyKV9/tHqSI2SWiSJO5pTnA2wVzACAAAAAAS2qvf9fvfVUH5WtsVxjxmskpGjYTQV34LwvQQw1y9wIFbAAgAAAAAE0+FKuK7HxbypvCeEJzMTcjOWE0ScYOlTBMUNlIv55hAAM5AH0AAAAFZAAgAAAAAH31lb/srBcrOXkzddCwAnclsR5/3QijEVgECs2JjOWBBXMAIAAAAABg7+prDT73YcCvLE5QbuIrqGcjLc5pQD2Miq0d29yrxgVsACAAAAAAetRiPwDSFWBzpWSWkOKWM6fKStRJ8SyObnpc79ux8p0AAzEwAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzExAH0AAAAFZAAgAAAAAFdthRhe2Q8CvxGIhjTJZv0Lk97GkHciTPxZ/mckLoNaBXMAIAAAAAAqOxsAr23LOVB0DIHbPf9UDJJRFXY2YoKbjhRqw5psbQVsACAAAAAA0G2GD8ZQjDBntjLpW4rqwKRS6HiUjL03g1N6chANozcAAzEyAH0AAAAFZAAgAAAAAMWymwwbvIeMqmnKWWifUqoCxOsdpnonM2qdLPyjqJO/BXMAIAAAAAB6IDmmpUhBD2zpRj8/y/kmOSXcjuIU14sNh6GKSsg2uwVsACAAAAAAWMFPNOk3EMSQDS9JGPSMIQP0oNGVugxXKKUrIPPlhHgAAzEzAH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzE0AH0AAAAFZAAgAAAAAJaRYmo8zqI2BEUzdSwp4tVRpPmVWsfydkYN3UHh6TMuBXMAIAAAAAAeD6mDnQeLlbC9i0sVgE8+RH6y+e94OJQ0tJ0PvblVSgVsACAAAAAAWp4jvretbDEsqEMzP/WLTnwOiJwCtfrCiB6m8k+yEMoAAzE1AH0AAAAFZAAgAAAAAAZZ538coNPwyRjhEwr5P8Xw32oWOJF+R+nfCGgy2qO3BXMAIAAAAACOPLnJlKwGNPDBReRKnHfteq0wFb3ezhrc7BVXs8RUHwVsACAAAAAA+lGesNk3+SyB/60rSvdQ2aN2vfJPR7llJVhufGTNhHkAAzE2AH0AAAAFZAAgAAAAAFH9l9GGA1I52atJV5jNUf1lx8jBjoEoVoME97v5GFJiBXMAIAAAAAC1qH3Kd78Dr9NGbw7y9D/XYBwv5h1LLO8la5OU7g8UkQVsACAAAAAArZ6atJCYrVfHB8dSNPOFf6nnDADBMJcIEj8ljPvxHp8AAzE3AH0AAAAFZAAgAAAAADtbVEI2tdkrowEMdkacD2w0Y3T3Ofi7PH6HmA6sP0c/BXMAIAAAAADuBSROnZHA+NgUPH8d0LnWFiDsM2bY8bzjC1+elSsIygVsACAAAAAAR0G2m+uANoWknkr/NerFcG+fECVxNIs0cqbY1t/U/0MAAzE4AH0AAAAFZAAgAAAAAAh3WpeMVlikPFYj9hLj+fmIqVt6omCSF75W3TPExyWpBXMAIAAAAAAsQkRmwqeVj2gGE03orb6PtrIzDt6dDU3hgSQi8E2wKgVsACAAAAAA3GHaRE2RAcaBRd8VzmYzWeBD2Gmy91eTK1k8YdWObZcAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
index 300202e22..7d799c785 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-DoublePrecision-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -315,7 +316,7 @@
                     "encryptedDoublePrecision": {
                       "$gt": {
                         "$binary": {
-                          "base64": "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",
+                          "base64": "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",
                           "subType": "06"
                         }
                       }
@@ -368,24 +369,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedDoublePrecision": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
similarity index 90%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
index 536415f3f..d95d95a11 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -304,7 +305,7 @@
                     "encryptedInt": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
index 6abd773da..b5f79c8cb 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
index 9d5bff1d1..e3217a2a7 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -295,7 +296,7 @@
                     "encryptedInt": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
@@ -339,24 +340,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedInt": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
index 4bf57700c..1b729d14e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -304,7 +305,7 @@
                 "encryptedInt": {
                   "$gt": {
                     "$binary": {
-                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
@@ -352,24 +353,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedInt": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
similarity index 90%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
index 6f6022e74..81ded9596 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -298,7 +299,7 @@
                 "encryptedInt": {
                   "$gt": {
                     "$binary": {
-                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
index 17d23b957..81120af32 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Int-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -306,7 +307,7 @@
                     "encryptedInt": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
@@ -356,24 +357,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedInt": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
similarity index 90%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
index 3f1c723bd..3c17a3238 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -304,7 +305,7 @@
                     "encryptedLong": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
index 972388c6c..db1e69a36 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
similarity index 85%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
index 89e189840..6e32f8d5e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -295,7 +296,7 @@
                     "encryptedLong": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
@@ -339,24 +340,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedLong": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
index 59342a343..2db5f700f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -304,7 +305,7 @@
                 "encryptedLong": {
                   "$gt": {
                     "$binary": {
-                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
@@ -352,24 +353,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedLong": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
similarity index 90%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
index 882e52170..365c7e5d5 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -298,7 +299,7 @@
                 "encryptedLong": {
                   "$gt": {
                     "$binary": {
-                      "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                      "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                       "subType": "06"
                     }
                   }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
similarity index 87%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
index 92e3e390a..3ee000b63 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-Long-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -306,7 +307,7 @@
                     "encryptedLong": {
                       "$gt": {
                         "$binary": {
-                          "base64": "CnEFAAADcGF5bG9hZABBBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVjACAAAAAAKs6X8gaa+AJ6PpxVicsk7iCXpSYIkQ5zB0KnXqlfCWgAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWMAIAAAAABYTWOKsDZ7cgPhiKDR2bE5CFGz4MuEwZbzZ0z46eGzBQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFYwAgAAAAABSqgKlxv5LXoxUO3zNmqGztlZhL2S150WiR/eycv7CWAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVjACAAAAAAfsofSP7nQHv8ic8ZW0aNlWxplS46Z+mywPR4rQk+wcgAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWMAIAAAAADu3L42J/oqNLe/XNYpodf2fhmPdcLhqO4J24o0hiveXwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFYwAgAAAAAAUljtCIvjRnLB2UPTEeRIz11Snl5SOBUNaXMXig4rqKAAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVjACAAAAAAD51NYesiO4Fo7w7iWBfqAFxEqkaDVctpvzZ28nT4SE8AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWMAIAAAAABJDtFhJ2tPbowp1UUmOCN/rqSqHRL1dtMu0c47vIlK4wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FYwAgAAAAAE6kvmXPqTnYIH4EJmNhy8OLVJZFOmdiBXLMorhELjKWAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVjACAAAAAA85AiE+bNFAYQTXQAFexgeczdVhf8FUnf16WzJlI/kmsAAAVlACAAAAAA65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+wSY20AAAAAAAAAAAAAEHBheWxvYWRJZAAAAAAAEGZpcnN0T3BlcmF0b3IAAQAAAAA=",
+                          "base64": "DUkFAAADcGF5bG9hZAAZBQAABGcABQUAAAMwAH0AAAAFZAAgAAAAALGGQ/CRD+pGLD53BZzWcCcYbuGLVEyjzXIx7b+ux/q2BXMAIAAAAACOC6mXEZL27P9hethZbtKYsTXKK+FpgQ9Axxmn9N/cCwVsACAAAAAA+MFEd8XfZSpbXKqqPC2L3TEFswkaG5Ff6aSgf8p+XVIAAzEAfQAAAAVkACAAAAAAtL3QIvnZqCF72eS6lKr8ilff7R6kiNklokiTuaU5wNsFcwAgAAAAAEtqr3/X731VB+VrbFcY8ZrJKRo2E0Fd+C8L0EMNcvcCBWwAIAAAAABNPhSriux8W8qbwnhCczE3IzlhNEnGDpUwTFDZSL+eYQADMgB9AAAABWQAIAAAAAB99ZW/7KwXKzl5M3XQsAJ3JbEef90IoxFYBArNiYzlgQVzACAAAAAAYO/qaw0+92HAryxOUG7iK6hnIy3OaUA9jIqtHdvcq8YFbAAgAAAAAHrUYj8A0hVgc6VklpDiljOnykrUSfEsjm56XO/bsfKdAAMzAH0AAAAFZAAgAAAAAOK8brUuc2onBNDRtfYMR736dHj4dQqXod8JG7tAMTsDBXMAIAAAAAAW6SrGAL6Bx0s7ZlsYULFfOAiYIGhEWu6md3r+Rk40awVsACAAAAAAIHYXP8RLcCboUmHN3+OlnEw1DxaLSnbTB9PdF228fFAAAzQAfQAAAAVkACAAAAAAV22FGF7ZDwK/EYiGNMlm/QuT3saQdyJM/Fn+ZyQug1oFcwAgAAAAACo7GwCvbcs5UHQMgds9/1QMklEVdjZigpuOFGrDmmxtBWwAIAAAAADQbYYPxlCMMGe2MulbiurApFLoeJSMvTeDU3pyEA2jNwADNQB9AAAABWQAIAAAAADFspsMG7yHjKppyllon1KqAsTrHaZ6JzNqnSz8o6iTvwVzACAAAAAAeiA5pqVIQQ9s6UY/P8v5Jjkl3I7iFNeLDYehikrINrsFbAAgAAAAAFjBTzTpNxDEkA0vSRj0jCED9KDRlboMVyilKyDz5YR4AAM2AH0AAAAFZAAgAAAAAPcLmtq+V1e+MRlZ7NHq1+mrRVBQje5zj685ZvdsfKvSBXMAIAAAAABdHz/3w2k5km97QN9m7oLFYJaVJneNlMboIlz5yUASQAVsACAAAAAAWbp8JVJnx8fEVAJFa7WMfMa7wXeP5M3C8MX20J/i9n0AAzcAfQAAAAVkACAAAAAAYfLwnoxK6XAGQrJFy8+TIJoq38ldBaO75h4zA4ZX5tQFcwAgAAAAAC2wk8UcJH5X5XGnDBYmel6srpBkzBhHtt3Jw1u5TSJ1BWwAIAAAAAA9/YU9eI3D7QbXKIw/3/gzWJ6MZrCYhG0j1wNKgRQp5wADOAB9AAAABWQAIAAAAADGvyrtKkIcaV17ynZA7b2k5Pz6OhvxdWNkDvDWJIja8wVzACAAAAAAOLypVKNxf/wR1G8OZjUUsTQzDYeNNhhITxGMSp7euS4FbAAgAAAAAA9EsxoV1B2DcQ1NJRwuxXnvVR+vkD0wbbDYEI/zFEnDAAM5AH0AAAAFZAAgAAAAAEocREw1L0g+roFUchJI2Yd0M0ME2bnErNUYnpyJP1SqBXMAIAAAAAAcE2/JK/8MoSeOchIuAkKh1X3ImoA7p8ujAZIfvIDo6QVsACAAAAAA+W0+zgLr85/PD7P9a94wk6MgNgrizx/XU9aCxAkp1IwAABJjbQAAAAAAAAAAAAAQcGF5bG9hZElkAAAAAAAQZmlyc3RPcGVyYXRvcgABAAAAAA==",
                           "subType": "06"
                         }
                       }
@@ -356,24 +357,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedLong": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               },
               "$db": "default"
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
similarity index 98%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
index 9eddf1c99..c28576554 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Range-WrongType.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.2.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
similarity index 90%
rename from tests/SpecTests/client-side-encryption/tests/fle2-Update.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
index 090f44f9a..5756ed828 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
@@ -233,7 +234,7 @@
                     "encryptedIndexed": {
                       "$eq": {
                         "$binary": {
-                          "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                          "base64": "DIkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVsACAAAAAAaZ9s3G+4znfxStxeOZwcZy1OhzjMGc5hjmdMN+b/w6kSY20AAAAAAAAAAAAA",
                           "subType": "06"
                         }
                       }
@@ -282,24 +283,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedIndexed": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
@@ -497,7 +480,7 @@
                     "encryptedIndexed": {
                       "$eq": {
                         "$binary": {
-                          "base64": "BbEAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVjACAAAAAA19X9v9NlWidu/wR5/C/7WUV54DfL5CkNmT5WYrhxdDcFZQAgAAAAAOuac/eRLYakKX6B0vZ1r3QodOQFfjqJD+xlGiPu4/PsEmNtAAAAAAAAAAAAAA==",
+                          "base64": "DIkAAAAFZAAgAAAAAPtVteJQAlgb2YMa/+7YWH00sbQPyt7L6Rb8OwBdMmL2BXMAIAAAAAAd44hgVKnEnTFlwNVC14oyc9OZOTspeymusqkRQj57nAVsACAAAAAAaZ9s3G+4znfxStxeOZwcZy1OhzjMGc5hjmdMN+b/w6kSY20AAAAAAAAAAAAA",
                           "subType": "06"
                         }
                       }
@@ -548,24 +531,6 @@
                       }
                     ]
                   }
-                },
-                "deleteTokens": {
-                  "default.default": {
-                    "encryptedIndexed": {
-                      "e": {
-                        "$binary": {
-                          "base64": "65pz95EthqQpfoHS9nWvdCh05AV+OokP7GUaI+7j8+w=",
-                          "subType": "00"
-                        }
-                      },
-                      "o": {
-                        "$binary": {
-                          "base64": "noN+05JsuO1oDg59yypIGj45i+eFH6HOTXOPpeZ//Mk=",
-                          "subType": "00"
-                        }
-                      }
-                    }
-                  }
                 }
               }
             },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
similarity index 99%
rename from tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json
rename to tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
index e70ca7c72..b18afb115 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2-validatorAndPartialFieldExpression.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
@@ -1,7 +1,8 @@
 {
   "runOn": [
     {
-      "minServerVersion": "6.0.0",
+      "minServerVersion": "7.0.0",
+      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",

From 03500cd3eb5b2c73762e37b7ee8ff53caa00551a Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 18 Apr 2023 09:50:34 +0800
Subject: [PATCH 277/321] Add non-breaking space back to PHPC display_name

---
 .evergreen/config.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 0ef7f6e76..7bb5ceb6d 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -625,15 +625,15 @@ axes:
     display_name: Driver Version
     values:
       - id: "oldest-supported"
-        display_name: "PHPC 1.14.0"
+        display_name: "PHPC 1.14.0"
         variables:
           EXTENSION_VERSION: "1.14.0"
       - id: "latest-stable"
-        display_name: "PHPC (stable)"
+        display_name: "PHPC (stable)"
         variables:
           EXTENSION_VERSION: "stable"
       - id: "latest-dev"
-        display_name: "PHPC (master)"
+        display_name: "PHPC (master)"
         variables:
           EXTENSION_BRANCH: "master"
 

From b70b2e3ffe573b1c46e776c46a2fb471035744ad Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Tue, 9 May 2023 08:50:08 +0200
Subject: [PATCH 278/321] PHPLIB-1087: Sync collection management tests (#1068)

* Test on MongoDB 7.0

* Update collection management tests

This syncs collection management tests with commit mongodb/specifications@0fa17f36d4bd4def1dd5acd30264f0e2cc026d6d
---
 .evergreen/config.yml                         |  6 +-
 .../timeseries-collection.json                | 65 +++++++++++++++++++
 2 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 76f1f6695..6a059e359 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -713,6 +713,10 @@ axes:
         display_name: "MongoDB rapid"
         variables:
            MONGODB_VERSION: "rapid"
+      - id: "7.0"
+        display_name: "MongoDB 7.0"
+        variables:
+           MONGODB_VERSION: "7.0"
       - id: "6.0"
         display_name: "MongoDB 6.0"
         variables:
@@ -876,7 +880,7 @@ buildvariants:
   display_name: "${os}, ${mongodb-versions}, ${php-edge-versions}, ${driver-versions}"
   exclude_spec:
     # Debian 9.2 only supports up to MongoDB 5.0
-    - { "os": "debian92", "mongodb-versions": ["6.0", "rapid", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
+    - { "os": "debian92", "mongodb-versions": ["6.0", "7.0", "rapid", "latest"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
     - { "os": "debian11", "mongodb-versions": ["3.6", "4.0", "4.2", "4.4", "5.0"], "php-edge-versions": "latest-stable", "driver-versions": "latest-stable" }
   tasks:
     - name: "test-standalone"
diff --git a/tests/UnifiedSpecTests/collection-management/timeseries-collection.json b/tests/UnifiedSpecTests/collection-management/timeseries-collection.json
index b5638fd36..8525056fd 100644
--- a/tests/UnifiedSpecTests/collection-management/timeseries-collection.json
+++ b/tests/UnifiedSpecTests/collection-management/timeseries-collection.json
@@ -250,6 +250,71 @@
           ]
         }
       ]
+    },
+    {
+      "description": "createCollection with bucketing options",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "7.0"
+        }
+      ],
+      "operations": [
+        {
+          "name": "dropCollection",
+          "object": "database0",
+          "arguments": {
+            "collection": "test"
+          }
+        },
+        {
+          "name": "createCollection",
+          "object": "database0",
+          "arguments": {
+            "collection": "test",
+            "timeseries": {
+              "timeField": "time",
+              "bucketMaxSpanSeconds": 3600,
+              "bucketRoundingSeconds": 3600
+            }
+          }
+        },
+        {
+          "name": "assertCollectionExists",
+          "object": "testRunner",
+          "arguments": {
+            "databaseName": "ts-tests",
+            "collectionName": "test"
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "drop": "test"
+                },
+                "databaseName": "ts-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "create": "test",
+                  "timeseries": {
+                    "timeField": "time",
+                    "bucketMaxSpanSeconds": 3600,
+                    "bucketRoundingSeconds": 3600
+                  }
+                },
+                "databaseName": "ts-tests"
+              }
+            }
+          ]
+        }
+      ]
     }
   ]
 }

From 81e8b79fd4ce05daccd1a1f9bdbe096d75c1bf5c Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Tue, 9 May 2023 17:38:47 +0200
Subject: [PATCH 279/321] PHPLIB-1031: Test mongocryptd is not spawned when
 shared library is loaded (#1067)

* PHPLIB-1031: Test mongocryptd is not spawned when shared library is loaded

* Update libmongocrypt checks

* Remove obsolete auth database URI option

* Allow different server selection errors
---
 .../ClientSideEncryptionSpecTest.php          | 50 +++++++++++++++++--
 1 file changed, 45 insertions(+), 5 deletions(-)

diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index f63ceae3e..5dacac5e9 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -1029,6 +1029,44 @@ static function (self $test, ClientEncryption $clientEncryption, ClientEncryptio
         ];
     }
 
+    /**
+     * Prose test 8: Bypass Spawning mongocryptd (via loading shared library)
+     *
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/#via-loading-shared-library
+     */
+    public function testBypassSpawningMongocryptdViaLoadingSharedLibrary(): void
+    {
+        if (! static::isCryptSharedLibAvailable()) {
+            $this->markTestSkipped('Bypass spawning of mongocryptd cannot be tested when crypt_shared is not available');
+        }
+
+        $autoEncryptionOpts = [
+            'keyVaultNamespace' => 'keyvault.datakeys',
+            'kmsProviders' => [
+                'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)],
+            ],
+            'schemaMap' => [
+                'db.coll' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-schema.json')),
+            ],
+            'extraOptions' => [
+                'mongocryptdBypassSpawn' => true,
+                'mongocryptdURI' => 'mongodb://localhost:27021/?serverSelectionTimeoutMS=1000',
+                'mongocryptdSpawnArgs' => ['--pidfilepath=bypass-spawning-mongocryptd.pid', '--port=27021'],
+                'cryptSharedLibRequired' => true,
+            ],
+        ];
+
+        $clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]);
+
+        $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']);
+
+        $clientMongocryptd = static::createTestClient('mongodb://localhost:27021/?serverSelectionTimeoutMS=1000');
+
+        $this->expectException(ConnectionTimeoutException::class);
+        $this->expectExceptionMessageMatches('#(No suitable servers found)|(No servers yet eligible for rescan)#');
+        $clientMongocryptd->getManager()->selectServer();
+    }
+
     /**
      * Prose test 8: Bypass Spawning mongocryptd (via mongocryptdBypassSpawn)
      *
@@ -1054,7 +1092,7 @@ public function testBypassSpawningMongocryptdViaBypassSpawn(): void
             ],
             'extraOptions' => [
                 'mongocryptdBypassSpawn' => true,
-                'mongocryptdURI' => 'mongodb://localhost:27021/db?serverSelectionTimeoutMS=1000',
+                'mongocryptdURI' => 'mongodb://localhost:27021/?serverSelectionTimeoutMS=1000',
                 'mongocryptdSpawnArgs' => ['--pidfilepath=bypass-spawning-mongocryptd.pid', '--port=27021'],
             ],
         ];
@@ -1100,10 +1138,11 @@ public function testBypassSpawningMongocryptdViaBypassAutoEncryption(): void
 
         $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']);
 
-        $clientMongocryptd = static::createTestClient('mongodb://localhost:27021');
+        $clientMongocryptd = static::createTestClient('mongodb://localhost:27021/?serverSelectionTimeoutMS=1000');
 
         $this->expectException(ConnectionTimeoutException::class);
-        $clientMongocryptd->selectDatabase('db')->command(['ping' => 1]);
+        $this->expectExceptionMessageMatches('#(No suitable servers found)|(No servers yet eligible for rescan)#');
+        $clientMongocryptd->getManager()->selectServer();
     }
 
     /**
@@ -1133,10 +1172,11 @@ public function testBypassSpawningMongocryptdViaBypassQueryAnalysis(): void
 
         $clientEncrypted->selectCollection('db', 'coll')->insertOne(['unencrypted' => 'test']);
 
-        $clientMongocryptd = static::createTestClient('mongodb://localhost:27021');
+        $clientMongocryptd = static::createTestClient('mongodb://localhost:27021/?serverSelectionTimeoutMS=1000');
 
         $this->expectException(ConnectionTimeoutException::class);
-        $clientMongocryptd->selectDatabase('db')->command(['ping' => 1]);
+        $this->expectExceptionMessageMatches('#(No suitable servers found)|(No servers yet eligible for rescan)#');
+        $clientMongocryptd->getManager()->selectServer();
     }
 
     /**

From f50276a1fb945f2fce437d0300456b8bfc26c147 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Thu, 11 May 2023 12:48:34 +0800
Subject: [PATCH 280/321] PHPLIB-1116: Add tests for runCommand spec (#1066)

Additional test runner changes were required to support runCommand spec tests.

Synced with mongodb/specifications@d697477053972de77fb0e67bbba5228151bf76dd
---
 tests/UnifiedSpecTests/Operation.php          |  14 +-
 tests/UnifiedSpecTests/UnifiedSpecTest.php    |  11 +
 tests/UnifiedSpecTests/Util.php               |   2 +-
 .../run-command/runCommand.json               | 573 ++++++++++++++++++
 4 files changed, 595 insertions(+), 5 deletions(-)
 create mode 100644 tests/UnifiedSpecTests/run-command/runCommand.json

diff --git a/tests/UnifiedSpecTests/Operation.php b/tests/UnifiedSpecTests/Operation.php
index 54f634b02..d2793a239 100644
--- a/tests/UnifiedSpecTests/Operation.php
+++ b/tests/UnifiedSpecTests/Operation.php
@@ -683,10 +683,16 @@ function (CollectionInfo $info) {
                 assertArrayHasKey('command', $args);
                 assertInstanceOf(stdClass::class, $args['command']);
 
-                return $database->command(
-                    $args['command'],
-                    array_diff_key($args, ['command' => 1])
-                )->toArray()[0];
+                // Note: commandName is not used by PHP
+                $options = array_diff_key($args, ['command' => 1, 'commandName' => 1]);
+
+                /* runCommand spec tests may execute commands that return a
+                 * cursor (e.g. aggregate). PHPC creates a cursor automatically
+                 * so cannot return the original command result. Existing spec
+                 * tests do not evaluate the result, so we can return null here.
+                 * If that changes down the line, we can use command monitoring
+                 * to capture and return the command result. */
+                return $database->command($args['command'], $options)->toArray()[0] ?? null;
 
             default:
                 Assert::fail('Unsupported database operation: ' . $this->name);
diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php
index 8ed1849de..b86b14f03 100644
--- a/tests/UnifiedSpecTests/UnifiedSpecTest.php
+++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php
@@ -168,6 +168,17 @@ public function provideLoadBalancers()
         return $this->provideTests(__DIR__ . '/load-balancers/*.json');
     }
 
+    /** @dataProvider provideRunCommandTests */
+    public function testRunCommand(UnifiedTestCase $test): void
+    {
+        self::$runner->run($test);
+    }
+
+    public function provideRunCommandTests()
+    {
+        return $this->provideTests(__DIR__ . '/run-command/*.json');
+    }
+
     /** @dataProvider provideSessionsTests */
     public function testSessions(UnifiedTestCase $test): void
     {
diff --git a/tests/UnifiedSpecTests/Util.php b/tests/UnifiedSpecTests/Util.php
index d9b3b3898..351d9ad0f 100644
--- a/tests/UnifiedSpecTests/Util.php
+++ b/tests/UnifiedSpecTests/Util.php
@@ -80,7 +80,7 @@ final class Util
             'listCollections' => ['authorizedCollections', 'filter', 'maxTimeMS', 'session'],
             'modifyCollection' => ['collection', 'changeStreamPreAndPostImages', 'index', 'validator'],
             // Note: commandName is not used by PHP
-            'runCommand' => ['command', 'session', 'commandName'],
+            'runCommand' => ['command', 'commandName', 'readPreference', 'session'],
         ],
         Collection::class => [
             'aggregate' => ['pipeline', 'session', 'useCursor', 'allowDiskUse', 'batchSize', 'bypassDocumentValidation', 'collation', 'comment', 'explain', 'hint', 'let', 'maxAwaitTimeMS', 'maxTimeMS'],
diff --git a/tests/UnifiedSpecTests/run-command/runCommand.json b/tests/UnifiedSpecTests/run-command/runCommand.json
new file mode 100644
index 000000000..9c7f912f9
--- /dev/null
+++ b/tests/UnifiedSpecTests/run-command/runCommand.json
@@ -0,0 +1,573 @@
+{
+  "description": "runCommand",
+  "schemaVersion": "1.3",
+  "createEntities": [
+    {
+      "client": {
+        "id": "client",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "db",
+        "client": "client",
+        "databaseName": "db"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection",
+        "database": "db",
+        "collectionName": "collection"
+      }
+    },
+    {
+      "database": {
+        "id": "dbWithRC",
+        "client": "client",
+        "databaseName": "dbWithRC",
+        "databaseOptions": {
+          "readConcern": {
+            "level": "local"
+          }
+        }
+      }
+    },
+    {
+      "database": {
+        "id": "dbWithWC",
+        "client": "client",
+        "databaseName": "dbWithWC",
+        "databaseOptions": {
+          "writeConcern": {
+            "w": 0
+          }
+        }
+      }
+    },
+    {
+      "session": {
+        "id": "session",
+        "client": "client"
+      }
+    },
+    {
+      "client": {
+        "id": "clientWithStableApi",
+        "observeEvents": [
+          "commandStartedEvent"
+        ],
+        "serverApi": {
+          "version": "1",
+          "strict": true
+        }
+      }
+    },
+    {
+      "database": {
+        "id": "dbWithStableApi",
+        "client": "clientWithStableApi",
+        "databaseName": "dbWithStableApi"
+      }
+    }
+  ],
+  "initialData": [
+    {
+      "collectionName": "collection",
+      "databaseName": "db",
+      "documents": []
+    }
+  ],
+  "tests": [
+    {
+      "description": "always attaches $db and implicit lsid to given command and omits default readPreference",
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "db",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1,
+                  "$db": "db",
+                  "lsid": {
+                    "$$exists": true
+                  },
+                  "$readPreference": {
+                    "$$exists": false
+                  }
+                },
+                "commandName": "ping"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "attaches the provided session lsid to given command",
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "db",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            },
+            "session": "session"
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1,
+                  "lsid": {
+                    "$$sessionLsid": "session"
+                  },
+                  "$db": "db"
+                },
+                "commandName": "ping"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "attaches the provided $readPreference to given command",
+      "runOnRequirements": [
+        {
+          "topologies": [
+            "replicaset",
+            "sharded-replicaset",
+            "load-balanced",
+            "sharded"
+          ]
+        }
+      ],
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "db",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            },
+            "readPreference": {
+              "mode": "nearest"
+            }
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1,
+                  "$readPreference": {
+                    "mode": "nearest"
+                  },
+                  "$db": "db"
+                },
+                "commandName": "ping"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "does not attach $readPreference to given command on standalone",
+      "runOnRequirements": [
+        {
+          "topologies": [
+            "single"
+          ]
+        }
+      ],
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "db",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            },
+            "readPreference": {
+              "mode": "nearest"
+            }
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1,
+                  "$readPreference": {
+                    "$$exists": false
+                  },
+                  "$db": "db"
+                },
+                "commandName": "ping"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "does not attach primary $readPreference to given command",
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "db",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            },
+            "readPreference": {
+              "mode": "primary"
+            }
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1,
+                  "$readPreference": {
+                    "$$exists": false
+                  },
+                  "$db": "db"
+                },
+                "commandName": "ping"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "does not inherit readConcern specified at the db level",
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "dbWithRC",
+          "arguments": {
+            "commandName": "aggregate",
+            "command": {
+              "aggregate": "collection",
+              "pipeline": [],
+              "cursor": {}
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "aggregate": "collection",
+                  "readConcern": {
+                    "$$exists": false
+                  },
+                  "$db": "dbWithRC"
+                },
+                "commandName": "aggregate"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "does not inherit writeConcern specified at the db level",
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "dbWithWC",
+          "arguments": {
+            "commandName": "insert",
+            "command": {
+              "insert": "collection",
+              "documents": [
+                {
+                  "_id": 1
+                }
+              ],
+              "ordered": true
+            }
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "collection",
+                  "writeConcern": {
+                    "$$exists": false
+                  },
+                  "$db": "dbWithWC"
+                },
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "does not retry retryable errors on given command",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "4.2"
+        }
+      ],
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "ping"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "db",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isClientError": true
+          }
+        }
+      ]
+    },
+    {
+      "description": "attaches transaction fields to given command",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "4.0",
+          "topologies": [
+            "replicaset"
+          ]
+        },
+        {
+          "minServerVersion": "4.2",
+          "topologies": [
+            "sharded-replicaset",
+            "load-balanced"
+          ]
+        }
+      ],
+      "operations": [
+        {
+          "name": "withTransaction",
+          "object": "session",
+          "arguments": {
+            "callback": [
+              {
+                "name": "runCommand",
+                "object": "db",
+                "arguments": {
+                  "session": "session",
+                  "commandName": "insert",
+                  "command": {
+                    "insert": "collection",
+                    "documents": [
+                      {
+                        "_id": 2
+                      }
+                    ],
+                    "ordered": true
+                  }
+                },
+                "expectResult": {
+                  "$$unsetOrMatches": {
+                    "insertedId": {
+                      "$$unsetOrMatches": 1
+                    }
+                  }
+                }
+              }
+            ]
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "collection",
+                  "documents": [
+                    {
+                      "_id": 2
+                    }
+                  ],
+                  "ordered": true,
+                  "lsid": {
+                    "$$sessionLsid": "session"
+                  },
+                  "txnNumber": 1,
+                  "startTransaction": true,
+                  "autocommit": false,
+                  "readConcern": {
+                    "$$exists": false
+                  },
+                  "writeConcern": {
+                    "$$exists": false
+                  }
+                },
+                "commandName": "insert",
+                "databaseName": "db"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "commitTransaction": 1,
+                  "lsid": {
+                    "$$sessionLsid": "session"
+                  },
+                  "txnNumber": 1,
+                  "autocommit": false,
+                  "writeConcern": {
+                    "$$exists": false
+                  },
+                  "readConcern": {
+                    "$$exists": false
+                  }
+                },
+                "commandName": "commitTransaction",
+                "databaseName": "admin"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "attaches apiVersion fields to given command when stableApi is configured on the client",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "5.0"
+        }
+      ],
+      "operations": [
+        {
+          "name": "runCommand",
+          "object": "dbWithStableApi",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectResult": {
+            "ok": 1
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "clientWithStableApi",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1,
+                  "$db": "dbWithStableApi",
+                  "apiVersion": "1",
+                  "apiStrict": true,
+                  "apiDeprecationErrors": {
+                    "$$unsetOrMatches": false
+                  }
+                },
+                "commandName": "ping"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

From 5a4ee68ba0f5496b34ebfb58c7628a0de380665c Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Sat, 13 May 2023 22:12:19 +0800
Subject: [PATCH 281/321] PHPLIB-1132: Sync unified spec tests for revised
 runOnRequirements (#1065)

Synced to mongodb/specifications@474ddfcc335225df4410986be2b10ae41a736d20
---
 tests/UnifiedSpecTests/UnifiedSpecTest.php    |   11 +
 .../change-streams-clusterTime.json           |    1 -
 .../change-streams-disambiguatedPaths.json    |    1 -
 .../change-streams/change-streams-errors.json |    4 +-
 .../change-streams-pre_and_post_images.json   |    2 +-
 .../change-streams-resume-allowlist.json      |    2 +-
 .../change-streams-resume-errorLabels.json    |    2 +-
 .../change-streams-showExpandedEvents.json    |    2 -
 .../bulkWrite-serverErrors.json               |  205 ++
 .../retryable-writes/handshakeError.json      | 1797 +++++++++++++++++
 .../insertOne-noWritesPerformedError.json     |   90 +
 .../insertOne-serverErrors.json               |  173 ++
 .../driver-sessions-dirty-session-errors.json |    2 +-
 ...t-sessions-default-causal-consistency.json |  318 +++
 .../snapshot-sessions-unsupported-ops.json    |    2 +-
 .../sessions/snapshot-sessions.json           |    2 +-
 .../transactions/mongos-unpin.json            |    2 +-
 .../collectionData-createOptions.json         |   32 +-
 .../UnifiedSpecTests/valid-pass/poc-crud.json |    2 +-
 .../valid-pass/poc-retryable-writes.json      |    6 +-
 .../valid-pass/poc-sessions.json              |    2 +-
 .../poc-transactions-convenient-api.json      |    2 +-
 .../poc-transactions-mongos-pin-auto.json     |    2 +-
 .../valid-pass/poc-transactions.json          |    6 +-
 .../versioned-api/transaction-handling.json   |    6 +-
 25 files changed, 2637 insertions(+), 37 deletions(-)
 create mode 100644 tests/UnifiedSpecTests/retryable-writes/bulkWrite-serverErrors.json
 create mode 100644 tests/UnifiedSpecTests/retryable-writes/handshakeError.json
 create mode 100644 tests/UnifiedSpecTests/retryable-writes/insertOne-noWritesPerformedError.json
 create mode 100644 tests/UnifiedSpecTests/retryable-writes/insertOne-serverErrors.json
 create mode 100644 tests/UnifiedSpecTests/sessions/implicit-sessions-default-causal-consistency.json

diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php
index b86b14f03..730e59e0d 100644
--- a/tests/UnifiedSpecTests/UnifiedSpecTest.php
+++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php
@@ -168,6 +168,17 @@ public function provideLoadBalancers()
         return $this->provideTests(__DIR__ . '/load-balancers/*.json');
     }
 
+    /** @dataProvider provideRetryableWritesTests */
+    public function testRetryableWrites(UnifiedTestCase $test): void
+    {
+        self::$runner->run($test);
+    }
+
+    public function provideRetryableWritesTests()
+    {
+        return $this->provideTests(__DIR__ . '/retryable-writes/*.json');
+    }
+
     /** @dataProvider provideRunCommandTests */
     public function testRunCommand(UnifiedTestCase $test): void
     {
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json b/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json
index 55b4ae3fb..2b09e548f 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-clusterTime.json
@@ -28,7 +28,6 @@
       "minServerVersion": "4.0.0",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
         "load-balanced",
         "sharded"
       ],
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json b/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json
index 91d8e66da..e6cc5ef66 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-disambiguatedPaths.json
@@ -28,7 +28,6 @@
       "minServerVersion": "6.1.0",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
         "load-balanced",
         "sharded"
       ],
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json
index 04fe8f04f..65e99e541 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-errors.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-errors.json
@@ -145,7 +145,7 @@
           "minServerVersion": "4.1.11",
           "topologies": [
             "replicaset",
-            "sharded-replicaset",
+            "sharded",
             "load-balanced"
           ]
         }
@@ -190,7 +190,7 @@
           "minServerVersion": "4.2",
           "topologies": [
             "replicaset",
-            "sharded-replicaset",
+            "sharded",
             "load-balanced"
           ]
         }
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json b/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json
index 8beefb2bc..e62fc0345 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-pre_and_post_images.json
@@ -6,7 +6,7 @@
       "minServerVersion": "6.0.0",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
+        "sharded",
         "load-balanced"
       ],
       "serverless": "forbid"
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json
index b4953ec73..1ec72b432 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-allowlist.json
@@ -6,7 +6,7 @@
       "minServerVersion": "3.6",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
+        "sharded",
         "load-balanced"
       ],
       "serverless": "forbid"
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json
index f5f4505a9..7fd70108f 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-resume-errorLabels.json
@@ -6,7 +6,7 @@
       "minServerVersion": "4.3.1",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
+        "sharded",
         "load-balanced"
       ],
       "serverless": "forbid"
diff --git a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json
index a59a81849..b9594e0c1 100644
--- a/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json
+++ b/tests/UnifiedSpecTests/change-streams/change-streams-showExpandedEvents.json
@@ -6,7 +6,6 @@
       "minServerVersion": "6.0.0",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
         "sharded"
       ],
       "serverless": "forbid"
@@ -463,7 +462,6 @@
       "runOnRequirements": [
         {
           "topologies": [
-            "sharded-replicaset",
             "sharded"
           ]
         }
diff --git a/tests/UnifiedSpecTests/retryable-writes/bulkWrite-serverErrors.json b/tests/UnifiedSpecTests/retryable-writes/bulkWrite-serverErrors.json
new file mode 100644
index 000000000..aed210ec2
--- /dev/null
+++ b/tests/UnifiedSpecTests/retryable-writes/bulkWrite-serverErrors.json
@@ -0,0 +1,205 @@
+{
+  "description": "retryable-writes bulkWrite serverErrors",
+  "schemaVersion": "1.0",
+  "runOnRequirements": [
+    {
+      "minServerVersion": "3.6",
+      "topologies": [
+        "replicaset"
+      ]
+    }
+  ],
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "retryable-writes-tests"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "coll"
+      }
+    }
+  ],
+  "initialData": [
+    {
+      "collectionName": "coll",
+      "databaseName": "retryable-writes-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": 11
+        },
+        {
+          "_id": 2,
+          "x": 22
+        }
+      ]
+    }
+  ],
+  "tests": [
+    {
+      "description": "BulkWrite succeeds after retryable writeConcernError in first batch",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "4.0",
+          "topologies": [
+            "replicaset"
+          ]
+        },
+        {
+          "minServerVersion": "4.1.7",
+          "topologies": [
+            "sharded"
+          ]
+        }
+      ],
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client0",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "insert"
+                ],
+                "errorLabels": [
+                  "RetryableWriteError"
+                ],
+                "writeConcernError": {
+                  "code": 91,
+                  "errmsg": "Replication is being shut down"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "bulkWrite",
+          "object": "collection0",
+          "arguments": {
+            "requests": [
+              {
+                "insertOne": {
+                  "document": {
+                    "_id": 3,
+                    "x": 33
+                  }
+                }
+              },
+              {
+                "deleteOne": {
+                  "filter": {
+                    "_id": 2
+                  }
+                }
+              }
+            ]
+          },
+          "expectResult": {
+            "deletedCount": 1,
+            "insertedCount": 1,
+            "matchedCount": 0,
+            "modifiedCount": 0,
+            "upsertedCount": 0,
+            "insertedIds": {
+              "$$unsetOrMatches": {
+                "0": 3
+              }
+            },
+            "upsertedIds": {}
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "coll",
+                  "documents": [
+                    {
+                      "_id": 3,
+                      "x": 33
+                    }
+                  ]
+                },
+                "commandName": "insert",
+                "databaseName": "retryable-writes-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "coll",
+                  "documents": [
+                    {
+                      "_id": 3,
+                      "x": 33
+                    }
+                  ]
+                },
+                "commandName": "insert",
+                "databaseName": "retryable-writes-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "delete": "coll",
+                  "deletes": [
+                    {
+                      "q": {
+                        "_id": 2
+                      },
+                      "limit": 1
+                    }
+                  ]
+                },
+                "commandName": "delete",
+                "databaseName": "retryable-writes-tests"
+              }
+            }
+          ]
+        }
+      ],
+      "outcome": [
+        {
+          "collectionName": "coll",
+          "databaseName": "retryable-writes-tests",
+          "documents": [
+            {
+              "_id": 1,
+              "x": 11
+            },
+            {
+              "_id": 3,
+              "x": 33
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/UnifiedSpecTests/retryable-writes/handshakeError.json b/tests/UnifiedSpecTests/retryable-writes/handshakeError.json
new file mode 100644
index 000000000..df37bd723
--- /dev/null
+++ b/tests/UnifiedSpecTests/retryable-writes/handshakeError.json
@@ -0,0 +1,1797 @@
+{
+  "description": "retryable writes handshake failures",
+  "schemaVersion": "1.3",
+  "runOnRequirements": [
+    {
+      "minServerVersion": "4.2",
+      "topologies": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ],
+      "auth": true
+    }
+  ],
+  "createEntities": [
+    {
+      "client": {
+        "id": "client",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "connectionCheckOutStartedEvent",
+          "commandStartedEvent",
+          "commandSucceededEvent",
+          "commandFailedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database",
+        "client": "client",
+        "databaseName": "retryable-writes-handshake-tests"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection",
+        "database": "database",
+        "collectionName": "coll"
+      }
+    }
+  ],
+  "initialData": [
+    {
+      "collectionName": "coll",
+      "databaseName": "retryable-writes-handshake-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": 11
+        }
+      ]
+    }
+  ],
+  "tests": [
+    {
+      "description": "collection.insertOne succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "insertOne",
+          "object": "collection",
+          "arguments": {
+            "document": {
+              "_id": 2,
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.insertOne succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "insertOne",
+          "object": "collection",
+          "arguments": {
+            "document": {
+              "_id": 2,
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.insertMany succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "insertMany",
+          "object": "collection",
+          "arguments": {
+            "documents": [
+              {
+                "_id": 2,
+                "x": 22
+              }
+            ]
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.insertMany succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "insertMany",
+          "object": "collection",
+          "arguments": {
+            "documents": [
+              {
+                "_id": 2,
+                "x": 22
+              }
+            ]
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.deleteOne succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "deleteOne",
+          "object": "collection",
+          "arguments": {
+            "filter": {}
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "delete"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "delete"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.deleteOne succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "deleteOne",
+          "object": "collection",
+          "arguments": {
+            "filter": {}
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "delete"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "delete"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.replaceOne succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "replaceOne",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "replacement": {
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "update"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "update"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.replaceOne succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "replaceOne",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "replacement": {
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "update"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "update"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.updateOne succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "updateOne",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "update": {
+              "$set": {
+                "x": 22
+              }
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "update"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "update"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.updateOne succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "updateOne",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "update": {
+              "$set": {
+                "x": 22
+              }
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "update"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "update"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.findOneAndDelete succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "findOneAndDelete",
+          "object": "collection",
+          "arguments": {
+            "filter": {}
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "findAndModify"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "findAndModify"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.findOneAndDelete succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "findOneAndDelete",
+          "object": "collection",
+          "arguments": {
+            "filter": {}
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "findAndModify"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "findAndModify"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.findOneAndReplace succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "findOneAndReplace",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "replacement": {
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "findAndModify"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "findAndModify"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.findOneAndReplace succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "findOneAndReplace",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "replacement": {
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "findAndModify"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "findAndModify"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.findOneAndUpdate succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "update": {
+              "$set": {
+                "x": 22
+              }
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "findAndModify"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "findAndModify"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.findOneAndUpdate succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "findOneAndUpdate",
+          "object": "collection",
+          "arguments": {
+            "filter": {},
+            "update": {
+              "$set": {
+                "x": 22
+              }
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "findAndModify"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "findAndModify"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.bulkWrite succeeds after retryable handshake network error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "bulkWrite",
+          "object": "collection",
+          "arguments": {
+            "requests": [
+              {
+                "insertOne": {
+                  "document": {
+                    "_id": 2,
+                    "x": 22
+                  }
+                }
+              }
+            ]
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "collection.bulkWrite succeeds after retryable handshake server error (ShutdownInProgress)",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "ping",
+                  "saslContinue"
+                ],
+                "closeConnection": true
+              }
+            }
+          }
+        },
+        {
+          "name": "runCommand",
+          "object": "database",
+          "arguments": {
+            "commandName": "ping",
+            "command": {
+              "ping": 1
+            }
+          },
+          "expectError": {
+            "isError": true
+          }
+        },
+        {
+          "name": "bulkWrite",
+          "object": "collection",
+          "arguments": {
+            "requests": [
+              {
+                "insertOne": {
+                  "document": {
+                    "_id": 2,
+                    "x": 22
+                  }
+                }
+              }
+            ]
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "eventType": "cmap",
+          "events": [
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            },
+            {
+              "connectionCheckOutStartedEvent": {}
+            }
+          ]
+        },
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "ping": 1
+                },
+                "databaseName": "retryable-writes-handshake-tests"
+              }
+            },
+            {
+              "commandFailedEvent": {
+                "commandName": "ping"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/UnifiedSpecTests/retryable-writes/insertOne-noWritesPerformedError.json b/tests/UnifiedSpecTests/retryable-writes/insertOne-noWritesPerformedError.json
new file mode 100644
index 000000000..3194e91c5
--- /dev/null
+++ b/tests/UnifiedSpecTests/retryable-writes/insertOne-noWritesPerformedError.json
@@ -0,0 +1,90 @@
+{
+  "description": "retryable-writes insertOne noWritesPerformedErrors",
+  "schemaVersion": "1.0",
+  "runOnRequirements": [
+    {
+      "minServerVersion": "6.0",
+      "topologies": [
+        "replicaset"
+      ]
+    }
+  ],
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandFailedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "retryable-writes-tests"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "no-writes-performed-collection"
+      }
+    }
+  ],
+  "tests": [
+    {
+      "description": "InsertOne fails after NoWritesPerformed error",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client0",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 2
+              },
+              "data": {
+                "failCommands": [
+                  "insert"
+                ],
+                "errorCode": 64,
+                "errorLabels": [
+                  "NoWritesPerformed",
+                  "RetryableWriteError"
+                ]
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "object": "collection0",
+          "arguments": {
+            "document": {
+              "x": 1
+            }
+          },
+          "expectError": {
+            "errorCode": 64,
+            "errorLabelsContain": [
+              "NoWritesPerformed",
+              "RetryableWriteError"
+            ]
+          }
+        }
+      ],
+      "outcome": [
+        {
+          "collectionName": "no-writes-performed-collection",
+          "databaseName": "retryable-writes-tests",
+          "documents": []
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/UnifiedSpecTests/retryable-writes/insertOne-serverErrors.json b/tests/UnifiedSpecTests/retryable-writes/insertOne-serverErrors.json
new file mode 100644
index 000000000..a87f45169
--- /dev/null
+++ b/tests/UnifiedSpecTests/retryable-writes/insertOne-serverErrors.json
@@ -0,0 +1,173 @@
+{
+  "description": "retryable-writes insertOne serverErrors",
+  "schemaVersion": "1.0",
+  "runOnRequirements": [
+    {
+      "minServerVersion": "3.6",
+      "topologies": [
+        "replicaset"
+      ]
+    }
+  ],
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "retryable-writes-tests"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection0",
+        "database": "database0",
+        "collectionName": "coll"
+      }
+    }
+  ],
+  "initialData": [
+    {
+      "collectionName": "coll",
+      "databaseName": "retryable-writes-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": 11
+        },
+        {
+          "_id": 2,
+          "x": 22
+        }
+      ]
+    }
+  ],
+  "tests": [
+    {
+      "description": "InsertOne succeeds after retryable writeConcernError",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "4.0",
+          "topologies": [
+            "replicaset"
+          ]
+        },
+        {
+          "minServerVersion": "4.1.7",
+          "topologies": [
+            "sharded"
+          ]
+        }
+      ],
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client0",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "insert"
+                ],
+                "errorLabels": [
+                  "RetryableWriteError"
+                ],
+                "writeConcernError": {
+                  "code": 91,
+                  "errmsg": "Replication is being shut down"
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "object": "collection0",
+          "arguments": {
+            "document": {
+              "_id": 3,
+              "x": 33
+            }
+          },
+          "expectResult": {
+            "$$unsetOrMatches": {
+              "insertedId": {
+                "$$unsetOrMatches": 3
+              }
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "coll",
+                  "documents": [
+                    {
+                      "_id": 3,
+                      "x": 33
+                    }
+                  ]
+                },
+                "commandName": "insert",
+                "databaseName": "retryable-writes-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "coll",
+                  "documents": [
+                    {
+                      "_id": 3,
+                      "x": 33
+                    }
+                  ]
+                },
+                "commandName": "insert",
+                "databaseName": "retryable-writes-tests"
+              }
+            }
+          ]
+        }
+      ],
+      "outcome": [
+        {
+          "collectionName": "coll",
+          "databaseName": "retryable-writes-tests",
+          "documents": [
+            {
+              "_id": 1,
+              "x": 11
+            },
+            {
+              "_id": 2,
+              "x": 22
+            },
+            {
+              "_id": 3,
+              "x": 33
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json b/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json
index 361ea83d7..6aa1da1df 100644
--- a/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json
+++ b/tests/UnifiedSpecTests/sessions/driver-sessions-dirty-session-errors.json
@@ -11,7 +11,7 @@
     {
       "minServerVersion": "4.1.8",
       "topologies": [
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
diff --git a/tests/UnifiedSpecTests/sessions/implicit-sessions-default-causal-consistency.json b/tests/UnifiedSpecTests/sessions/implicit-sessions-default-causal-consistency.json
new file mode 100644
index 000000000..517c8ebc6
--- /dev/null
+++ b/tests/UnifiedSpecTests/sessions/implicit-sessions-default-causal-consistency.json
@@ -0,0 +1,318 @@
+{
+  "description": "implicit sessions default causal consistency",
+  "schemaVersion": "1.3",
+  "runOnRequirements": [
+    {
+      "minServerVersion": "4.2",
+      "topologies": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "createEntities": [
+    {
+      "client": {
+        "id": "client0",
+        "useMultipleMongoses": false,
+        "observeEvents": [
+          "commandStartedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database0",
+        "client": "client0",
+        "databaseName": "implicit-cc-tests"
+      }
+    },
+    {
+      "collection": {
+        "id": "collectionDefault",
+        "database": "database0",
+        "collectionName": "coll-default"
+      }
+    },
+    {
+      "collection": {
+        "id": "collectionSnapshot",
+        "database": "database0",
+        "collectionName": "coll-snapshot",
+        "collectionOptions": {
+          "readConcern": {
+            "level": "snapshot"
+          }
+        }
+      }
+    },
+    {
+      "collection": {
+        "id": "collectionlinearizable",
+        "database": "database0",
+        "collectionName": "coll-linearizable",
+        "collectionOptions": {
+          "readConcern": {
+            "level": "linearizable"
+          }
+        }
+      }
+    }
+  ],
+  "initialData": [
+    {
+      "collectionName": "coll-default",
+      "databaseName": "implicit-cc-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": "default"
+        }
+      ]
+    },
+    {
+      "collectionName": "coll-snapshot",
+      "databaseName": "implicit-cc-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": "snapshot"
+        }
+      ]
+    },
+    {
+      "collectionName": "coll-linearizable",
+      "databaseName": "implicit-cc-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": "linearizable"
+        }
+      ]
+    }
+  ],
+  "tests": [
+    {
+      "description": "readConcern is not sent on retried read in implicit session when readConcern level is not specified",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client0",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "find"
+                ],
+                "errorCode": 11600
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "object": "collectionDefault",
+          "arguments": {
+            "filter": {}
+          },
+          "expectResult": [
+            {
+              "_id": 1,
+              "x": "default"
+            }
+          ]
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "find": "coll-default",
+                  "filter": {},
+                  "readConcern": {
+                    "$$exists": false
+                  }
+                },
+                "databaseName": "implicit-cc-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "find": "coll-default",
+                  "filter": {},
+                  "readConcern": {
+                    "$$exists": false
+                  }
+                },
+                "databaseName": "implicit-cc-tests"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "afterClusterTime is not sent on retried read in implicit session when readConcern level is snapshot",
+      "runOnRequirements": [
+        {
+          "minServerVersion": "5.0"
+        }
+      ],
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client0",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "find"
+                ],
+                "errorCode": 11600
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "object": "collectionSnapshot",
+          "arguments": {
+            "filter": {}
+          },
+          "expectResult": [
+            {
+              "_id": 1,
+              "x": "snapshot"
+            }
+          ]
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "find": "coll-snapshot",
+                  "filter": {},
+                  "readConcern": {
+                    "level": "snapshot",
+                    "afterClusterTime": {
+                      "$$exists": false
+                    }
+                  }
+                },
+                "databaseName": "implicit-cc-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "find": "coll-snapshot",
+                  "filter": {},
+                  "readConcern": {
+                    "level": "snapshot",
+                    "afterClusterTime": {
+                      "$$exists": false
+                    }
+                  }
+                },
+                "databaseName": "implicit-cc-tests"
+              }
+            }
+          ]
+        }
+      ]
+    },
+    {
+      "description": "afterClusterTime is not sent on retried read in implicit session when readConcern level is linearizable",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client0",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "find"
+                ],
+                "errorCode": 11600
+              }
+            }
+          }
+        },
+        {
+          "name": "find",
+          "object": "collectionlinearizable",
+          "arguments": {
+            "filter": {}
+          },
+          "expectResult": [
+            {
+              "_id": 1,
+              "x": "linearizable"
+            }
+          ]
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client0",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "find": "coll-linearizable",
+                  "filter": {},
+                  "readConcern": {
+                    "level": "linearizable",
+                    "afterClusterTime": {
+                      "$$exists": false
+                    }
+                  }
+                },
+                "databaseName": "implicit-cc-tests"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "find": "coll-linearizable",
+                  "filter": {},
+                  "readConcern": {
+                    "level": "linearizable",
+                    "afterClusterTime": {
+                      "$$exists": false
+                    }
+                  }
+                },
+                "databaseName": "implicit-cc-tests"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json b/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json
index 1021b7f26..c41f74d33 100644
--- a/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json
+++ b/tests/UnifiedSpecTests/sessions/snapshot-sessions-unsupported-ops.json
@@ -6,7 +6,7 @@
       "minServerVersion": "5.0",
       "topologies": [
         "replicaset",
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
diff --git a/tests/UnifiedSpecTests/sessions/snapshot-sessions.json b/tests/UnifiedSpecTests/sessions/snapshot-sessions.json
index 75b577b03..260f8b6f4 100644
--- a/tests/UnifiedSpecTests/sessions/snapshot-sessions.json
+++ b/tests/UnifiedSpecTests/sessions/snapshot-sessions.json
@@ -6,7 +6,7 @@
       "minServerVersion": "5.0",
       "topologies": [
         "replicaset",
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
diff --git a/tests/UnifiedSpecTests/transactions/mongos-unpin.json b/tests/UnifiedSpecTests/transactions/mongos-unpin.json
index 4f7ae4379..356f4fd9b 100644
--- a/tests/UnifiedSpecTests/transactions/mongos-unpin.json
+++ b/tests/UnifiedSpecTests/transactions/mongos-unpin.json
@@ -5,7 +5,7 @@
     {
       "minServerVersion": "4.2",
       "topologies": [
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
diff --git a/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json b/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json
index 64f8fb02f..19edc2247 100644
--- a/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json
+++ b/tests/UnifiedSpecTests/valid-pass/collectionData-createOptions.json
@@ -49,19 +49,29 @@
       "description": "collection is created with the correct options",
       "operations": [
         {
-          "name": "runCommand",
-          "object": "database0",
+          "object": "collection0",
+          "name": "aggregate",
           "arguments": {
-            "commandName": "collStats",
-            "command": {
-              "collStats": "coll0",
-              "scale": 1
-            }
+            "pipeline": [
+              {
+                "$collStats": {
+                  "storageStats": {}
+                }
+              },
+              {
+                "$project": {
+                  "capped": "$storageStats.capped",
+                  "maxSize": "$storageStats.maxSize"
+                }
+              }
+            ]
           },
-          "expectResult": {
-            "capped": true,
-            "maxSize": 4096
-          }
+          "expectResult": [
+            {
+              "capped": true,
+              "maxSize": 4096
+            }
+          ]
         }
       ]
     }
diff --git a/tests/UnifiedSpecTests/valid-pass/poc-crud.json b/tests/UnifiedSpecTests/valid-pass/poc-crud.json
index 0790d9b78..94e4ec568 100644
--- a/tests/UnifiedSpecTests/valid-pass/poc-crud.json
+++ b/tests/UnifiedSpecTests/valid-pass/poc-crud.json
@@ -322,7 +322,7 @@
           "minServerVersion": "4.1.0",
           "topologies": [
             "replicaset",
-            "sharded-replicaset"
+            "sharded"
           ],
           "serverless": "forbid"
         }
diff --git a/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json b/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json
index 50160799f..da72b7f27 100644
--- a/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json
+++ b/tests/UnifiedSpecTests/valid-pass/poc-retryable-writes.json
@@ -253,7 +253,7 @@
         {
           "minServerVersion": "4.1.7",
           "topologies": [
-            "sharded-replicaset"
+            "sharded"
           ]
         }
       ],
@@ -345,7 +345,7 @@
         {
           "minServerVersion": "4.1.7",
           "topologies": [
-            "sharded-replicaset"
+            "sharded"
           ]
         }
       ],
@@ -414,7 +414,7 @@
         {
           "minServerVersion": "4.1.7",
           "topologies": [
-            "sharded-replicaset"
+            "sharded"
           ]
         }
       ],
diff --git a/tests/UnifiedSpecTests/valid-pass/poc-sessions.json b/tests/UnifiedSpecTests/valid-pass/poc-sessions.json
index 75f348942..117c9e7d0 100644
--- a/tests/UnifiedSpecTests/valid-pass/poc-sessions.json
+++ b/tests/UnifiedSpecTests/valid-pass/poc-sessions.json
@@ -264,7 +264,7 @@
         {
           "minServerVersion": "4.1.8",
           "topologies": [
-            "sharded-replicaset"
+            "sharded"
           ]
         }
       ],
diff --git a/tests/UnifiedSpecTests/valid-pass/poc-transactions-convenient-api.json b/tests/UnifiedSpecTests/valid-pass/poc-transactions-convenient-api.json
index 820ed6592..9ab44a9c5 100644
--- a/tests/UnifiedSpecTests/valid-pass/poc-transactions-convenient-api.json
+++ b/tests/UnifiedSpecTests/valid-pass/poc-transactions-convenient-api.json
@@ -11,7 +11,7 @@
     {
       "minServerVersion": "4.1.8",
       "topologies": [
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
diff --git a/tests/UnifiedSpecTests/valid-pass/poc-transactions-mongos-pin-auto.json b/tests/UnifiedSpecTests/valid-pass/poc-transactions-mongos-pin-auto.json
index a0b297d59..de08edec4 100644
--- a/tests/UnifiedSpecTests/valid-pass/poc-transactions-mongos-pin-auto.json
+++ b/tests/UnifiedSpecTests/valid-pass/poc-transactions-mongos-pin-auto.json
@@ -5,7 +5,7 @@
     {
       "minServerVersion": "4.1.8",
       "topologies": [
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
diff --git a/tests/UnifiedSpecTests/valid-pass/poc-transactions.json b/tests/UnifiedSpecTests/valid-pass/poc-transactions.json
index 0355ca206..2055a3b70 100644
--- a/tests/UnifiedSpecTests/valid-pass/poc-transactions.json
+++ b/tests/UnifiedSpecTests/valid-pass/poc-transactions.json
@@ -11,7 +11,7 @@
     {
       "minServerVersion": "4.1.8",
       "topologies": [
-        "sharded-replicaset"
+        "sharded"
       ]
     }
   ],
@@ -93,7 +93,7 @@
           "minServerVersion": "4.3.4",
           "topologies": [
             "replicaset",
-            "sharded-replicaset"
+            "sharded"
           ]
         }
       ],
@@ -203,7 +203,7 @@
           "minServerVersion": "4.3.4",
           "topologies": [
             "replicaset",
-            "sharded-replicaset"
+            "sharded"
           ]
         }
       ],
diff --git a/tests/UnifiedSpecTests/versioned-api/transaction-handling.json b/tests/UnifiedSpecTests/versioned-api/transaction-handling.json
index c00c5240a..32031296a 100644
--- a/tests/UnifiedSpecTests/versioned-api/transaction-handling.json
+++ b/tests/UnifiedSpecTests/versioned-api/transaction-handling.json
@@ -6,7 +6,7 @@
       "minServerVersion": "4.9",
       "topologies": [
         "replicaset",
-        "sharded-replicaset",
+        "sharded",
         "load-balanced"
       ]
     }
@@ -92,7 +92,7 @@
         {
           "topologies": [
             "replicaset",
-            "sharded-replicaset",
+            "sharded",
             "load-balanced"
           ]
         }
@@ -221,7 +221,7 @@
         {
           "topologies": [
             "replicaset",
-            "sharded-replicaset",
+            "sharded",
             "load-balanced"
           ]
         }

From 7dcdf8b9b029eaedef73499d7d4f43b67ecca878 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Mon, 15 May 2023 08:41:47 +0200
Subject: [PATCH 282/321] Use PHP 8.2 as latest-stable in edge versions (#1069)

---
 .evergreen/config.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 6a059e359..134e5c005 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -694,9 +694,9 @@ axes:
     display_name: PHP Version
     values:
       - id: "latest-stable"
-        display_name: "PHP 8.1"
+        display_name: "PHP 8.2"
         variables:
-          PHP_VERSION: "8.1"
+          PHP_VERSION: "8.2"
       - id: "oldest-supported"
         display_name: "PHP 7.2"
         variables:
@@ -868,7 +868,7 @@ buildvariants:
   display_name: "${os}, ${mongodb-edge-versions}, ${php-versions}, ${driver-versions}"
   exclude_spec:
     # Exclude "latest-stable" PHP version for Debian 11 (see: test-mongodb-versions matrix)
-    - { "os": "debian11", "mongodb-edge-versions": "latest-stable", "php-versions": "8.1", "driver-versions": "latest-stable" }
+    - { "os": "debian11", "mongodb-edge-versions": "latest-stable", "php-versions": "8.2", "driver-versions": "latest-stable" }
   tasks:
     - name: "test-standalone"
     - name: "test-replica_set"

From 339b8a25e2856c99aaa7852708b5830c859dcd55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= 
Date: Fri, 19 May 2023 13:26:00 +0200
Subject: [PATCH 283/321] Remove early returns for failed tests from tearDown
 methods (#1071)

---
 tests/Collection/FunctionalTestCase.php            | 6 ++----
 tests/DocumentationExamplesTest.php                | 6 ++----
 tests/Model/IndexInfoFunctionalTest.php            | 6 ++----
 tests/Operation/FunctionalTestCase.php             | 6 ++----
 tests/Operation/RenameCollectionFunctionalTest.php | 8 +++-----
 5 files changed, 11 insertions(+), 21 deletions(-)

diff --git a/tests/Collection/FunctionalTestCase.php b/tests/Collection/FunctionalTestCase.php
index 89aea89dc..f0855267f 100644
--- a/tests/Collection/FunctionalTestCase.php
+++ b/tests/Collection/FunctionalTestCase.php
@@ -24,12 +24,10 @@ public function setUp(): void
 
     public function tearDown(): void
     {
-        if ($this->hasFailed()) {
-            return;
+        if (! $this->hasFailed()) {
+            $this->dropCollection();
         }
 
-        $this->dropCollection();
-
         parent::tearDown();
     }
 }
diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index 5e0c592cf..c56e62df1 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -40,12 +40,10 @@ public function setUp(): void
 
     public function tearDown(): void
     {
-        if ($this->hasFailed()) {
-            return;
+        if (! $this->hasFailed()) {
+            $this->dropCollection();
         }
 
-        $this->dropCollection();
-
         parent::tearDown();
     }
 
diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php
index f9c437eac..a2b5868d7 100644
--- a/tests/Model/IndexInfoFunctionalTest.php
+++ b/tests/Model/IndexInfoFunctionalTest.php
@@ -20,12 +20,10 @@ public function setUp(): void
 
     public function tearDown(): void
     {
-        if ($this->hasFailed()) {
-            return;
+        if (! $this->hasFailed()) {
+            $this->collection->drop();
         }
 
-        $this->collection->drop();
-
         parent::tearDown();
     }
 
diff --git a/tests/Operation/FunctionalTestCase.php b/tests/Operation/FunctionalTestCase.php
index 4cf9f33cb..df1eebdda 100644
--- a/tests/Operation/FunctionalTestCase.php
+++ b/tests/Operation/FunctionalTestCase.php
@@ -20,12 +20,10 @@ public function setUp(): void
 
     public function tearDown(): void
     {
-        if ($this->hasFailed()) {
-            return;
+        if (! $this->hasFailed()) {
+            $this->dropCollection();
         }
 
-        $this->dropCollection();
-
         parent::tearDown();
     }
 
diff --git a/tests/Operation/RenameCollectionFunctionalTest.php b/tests/Operation/RenameCollectionFunctionalTest.php
index 198adc369..5f4b25b6a 100644
--- a/tests/Operation/RenameCollectionFunctionalTest.php
+++ b/tests/Operation/RenameCollectionFunctionalTest.php
@@ -31,13 +31,11 @@ public function setUp(): void
 
     public function tearDown(): void
     {
-        if ($this->hasFailed()) {
-            return;
+        if (! $this->hasFailed()) {
+            $operation = new DropCollection($this->getDatabaseName(), $this->toCollectionName);
+            $operation->execute($this->getPrimaryServer());
         }
 
-        $operation = new DropCollection($this->getDatabaseName(), $this->toCollectionName);
-        $operation->execute($this->getPrimaryServer());
-
         parent::tearDown();
     }
 

From 21e7ef8d8252a92848ccfffcf010699ed301c09e Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Wed, 24 May 2023 08:37:33 +0200
Subject: [PATCH 284/321] Update actions/checkout to v3 (#1074)

This fixes warnings about node 12 actions being deprecated.
---
 .github/workflows/coding-standards.yml | 2 +-
 .github/workflows/static-analysis.yml  | 2 +-
 .github/workflows/tests.yml            | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index e9207b68b..3476e5344 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -30,7 +30,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: Setup cache environment
         id: extcache
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 67c605e8c..fac516d73 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -30,7 +30,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
 
       - name: Setup cache environment
         id: extcache
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index cf30d09e6..4a67ff4ae 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -66,7 +66,7 @@ jobs:
 
     steps:
       - name: "Checkout"
-        uses: "actions/checkout@v2"
+        uses: "actions/checkout@v3"
         with:
           fetch-depth: 2
 

From cb57dc797cf6d85bc0bfe27054453a33ab3826e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= 
Date: Thu, 25 May 2023 06:06:36 +0200
Subject: [PATCH 285/321] PHPLIB-1056: Add missing types in reference doc
 (#1076)

Co-authored-by: Jeremy Mikola 
---
 docs/reference/method/MongoDBCollection-count.txt               | 2 +-
 docs/reference/method/MongoDBCollection-countDocuments.txt      | 2 +-
 docs/reference/method/MongoDBCollection-createIndex.txt         | 2 +-
 docs/reference/method/MongoDBCollection-deleteMany.txt          | 2 +-
 docs/reference/method/MongoDBCollection-deleteOne.txt           | 2 +-
 docs/reference/method/MongoDBCollection-distinct.txt            | 2 +-
 docs/reference/method/MongoDBCollection-dropIndex.txt           | 2 +-
 docs/reference/method/MongoDBCollection-find.txt                | 2 +-
 docs/reference/method/MongoDBCollection-findOne.txt             | 2 +-
 docs/reference/method/MongoDBCollection-findOneAndDelete.txt    | 2 +-
 docs/reference/method/MongoDBCollection-findOneAndReplace.txt   | 2 +-
 docs/reference/method/MongoDBCollection-findOneAndUpdate.txt    | 2 +-
 docs/reference/method/MongoDBCollection-insertOne.txt           | 2 +-
 docs/reference/method/MongoDBCollection-mapReduce.txt           | 2 +-
 docs/reference/method/MongoDBCollection-replaceOne.txt          | 2 +-
 docs/reference/method/MongoDBCollection-updateMany.txt          | 2 +-
 docs/reference/method/MongoDBCollection-updateOne.txt           | 2 +-
 docs/reference/method/MongoDBDatabase-command.txt               | 2 +-
 docs/reference/method/MongoDBDatabase-createCollection.txt      | 2 +-
 docs/reference/method/MongoDBDatabase-dropCollection.txt        | 2 +-
 docs/reference/method/MongoDBDatabase-modifyCollection.txt      | 2 +-
 docs/reference/method/MongoDBDatabase-selectCollection.txt      | 2 +-
 docs/reference/method/MongoDBDatabase__get.txt                  | 2 +-
 .../method/MongoDBGridFSBucket-downloadToStreamByName.txt       | 2 +-
 docs/reference/method/MongoDBGridFSBucket-find.txt              | 2 +-
 docs/reference/method/MongoDBGridFSBucket-findOne.txt           | 2 +-
 .../method/MongoDBGridFSBucket-getFileDocumentForStream.txt     | 2 +-
 .../reference/method/MongoDBGridFSBucket-getFileIdForStream.txt | 2 +-
 docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt  | 2 +-
 29 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/docs/reference/method/MongoDBCollection-count.txt b/docs/reference/method/MongoDBCollection-count.txt
index 012b3cb6f..1673ed91d 100644
--- a/docs/reference/method/MongoDBCollection-count.txt
+++ b/docs/reference/method/MongoDBCollection-count.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function count($filter = [], array $options = []): integer
+      function count(array|object $filter = [], array $options = []): integer
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-countDocuments.txt b/docs/reference/method/MongoDBCollection-countDocuments.txt
index 0b150361f..44b16c8e0 100644
--- a/docs/reference/method/MongoDBCollection-countDocuments.txt
+++ b/docs/reference/method/MongoDBCollection-countDocuments.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function countDocuments($filter = [], array $options = []): integer
+      function countDocuments(array|object $filter = [], array $options = []): integer
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-createIndex.txt b/docs/reference/method/MongoDBCollection-createIndex.txt
index 344242e0f..ceef2e7bc 100644
--- a/docs/reference/method/MongoDBCollection-createIndex.txt
+++ b/docs/reference/method/MongoDBCollection-createIndex.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function createIndex($key, array $options = []): string
+      function createIndex(array|object $key, array $options = []): string
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-deleteMany.txt b/docs/reference/method/MongoDBCollection-deleteMany.txt
index a9fc24c11..29ad2e833 100644
--- a/docs/reference/method/MongoDBCollection-deleteMany.txt
+++ b/docs/reference/method/MongoDBCollection-deleteMany.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function deleteMany($filter, array $options = []): MongoDB\DeleteResult
+      function deleteMany(array|object $filter, array $options = []): MongoDB\DeleteResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-deleteOne.txt b/docs/reference/method/MongoDBCollection-deleteOne.txt
index dcfb26285..6c888a961 100644
--- a/docs/reference/method/MongoDBCollection-deleteOne.txt
+++ b/docs/reference/method/MongoDBCollection-deleteOne.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function deleteOne($filter, array $options = []): MongoDB\DeleteResult
+      function deleteOne(array|object $filter, array $options = []): MongoDB\DeleteResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-distinct.txt b/docs/reference/method/MongoDBCollection-distinct.txt
index 7d5f7ee6d..24fd6761a 100644
--- a/docs/reference/method/MongoDBCollection-distinct.txt
+++ b/docs/reference/method/MongoDBCollection-distinct.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function distinct(string $fieldName, $filter = [], array $options = []): mixed[]
+      function distinct(string $fieldName, array|object $filter = [], array $options = []): mixed[]
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-dropIndex.txt b/docs/reference/method/MongoDBCollection-dropIndex.txt
index cefcf6763..0a7fbb53f 100644
--- a/docs/reference/method/MongoDBCollection-dropIndex.txt
+++ b/docs/reference/method/MongoDBCollection-dropIndex.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function dropIndex($indexName, array $options = []): array|object
+      function dropIndex(string|MongoDB\Model\IndexInfo $indexName, array $options = []): array|object
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-find.txt b/docs/reference/method/MongoDBCollection-find.txt
index 303b70421..4fe923893 100644
--- a/docs/reference/method/MongoDBCollection-find.txt
+++ b/docs/reference/method/MongoDBCollection-find.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function find($filter = [], array $options = []): MongoDB\Driver\Cursor
+      function find(array|object $filter = [], array $options = []): MongoDB\Driver\Cursor
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-findOne.txt b/docs/reference/method/MongoDBCollection-findOne.txt
index 5e4c32f3b..44829db30 100644
--- a/docs/reference/method/MongoDBCollection-findOne.txt
+++ b/docs/reference/method/MongoDBCollection-findOne.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function findOne($filter = [], array $options = []): array|object|null
+      function findOne(array|object $filter = [], array $options = []): array|object|null
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-findOneAndDelete.txt b/docs/reference/method/MongoDBCollection-findOneAndDelete.txt
index bdf20da9c..e5531f416 100644
--- a/docs/reference/method/MongoDBCollection-findOneAndDelete.txt
+++ b/docs/reference/method/MongoDBCollection-findOneAndDelete.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function findOneAndDelete($filter = [], array $options = []): object|null
+      function findOneAndDelete(array|object $filter = [], array $options = []): object|null
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-findOneAndReplace.txt b/docs/reference/method/MongoDBCollection-findOneAndReplace.txt
index 4b29d8ad5..66bd7f12f 100644
--- a/docs/reference/method/MongoDBCollection-findOneAndReplace.txt
+++ b/docs/reference/method/MongoDBCollection-findOneAndReplace.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function findOneAndReplace($filter, $replacement, array $options = []): object|null
+      function findOneAndReplace(array|object $filter, array|object $replacement, array $options = []): object|null
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt b/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt
index 65ea436dd..c903698b1 100644
--- a/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt
+++ b/docs/reference/method/MongoDBCollection-findOneAndUpdate.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function findOneAndUpdate($filter, $update, array $options = []): object|null
+      function findOneAndUpdate(array|object $filter, array|object $update, array $options = []): object|null
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-insertOne.txt b/docs/reference/method/MongoDBCollection-insertOne.txt
index aa4380500..dd6e2f220 100644
--- a/docs/reference/method/MongoDBCollection-insertOne.txt
+++ b/docs/reference/method/MongoDBCollection-insertOne.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function insertOne($document, array $options = []): MongoDB\InsertOneResult
+      function insertOne(array|object $document, array $options = []): MongoDB\InsertOneResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-mapReduce.txt b/docs/reference/method/MongoDBCollection-mapReduce.txt
index dc3d3b098..a38872bdc 100644
--- a/docs/reference/method/MongoDBCollection-mapReduce.txt
+++ b/docs/reference/method/MongoDBCollection-mapReduce.txt
@@ -24,7 +24,7 @@ Definition
 
    .. code-block:: php
 
-      function mapReduce($map, $reduce, $out, array $options = []): MongoDB\MapReduceResult
+      function mapReduce(MongoDB\BSON\JavascriptInterface $map, MongoDB\BSON\JavascriptInterface $reduce, string|array|object $out, array $options = []): MongoDB\MapReduceResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-replaceOne.txt b/docs/reference/method/MongoDBCollection-replaceOne.txt
index 9bb3d30cd..e42f993e9 100644
--- a/docs/reference/method/MongoDBCollection-replaceOne.txt
+++ b/docs/reference/method/MongoDBCollection-replaceOne.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function replaceOne($filter, $replacement, array $options = []): MongoDB\UpdateResult
+      function replaceOne(array|object $filter, array|object $replacement, array $options = []): MongoDB\UpdateResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-updateMany.txt b/docs/reference/method/MongoDBCollection-updateMany.txt
index c30978824..0e5f22b9d 100644
--- a/docs/reference/method/MongoDBCollection-updateMany.txt
+++ b/docs/reference/method/MongoDBCollection-updateMany.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function updateMany($filter, $update, array $options = []): MongoDB\UpdateResult
+      function updateMany(array|object $filter, array|object $update, array $options = []): MongoDB\UpdateResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBCollection-updateOne.txt b/docs/reference/method/MongoDBCollection-updateOne.txt
index 5fe29405c..2b930e232 100644
--- a/docs/reference/method/MongoDBCollection-updateOne.txt
+++ b/docs/reference/method/MongoDBCollection-updateOne.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function updateOne($filter, $update, array $options = []): MongoDB\UpdateResult
+      function updateOne(array|object $filter, array|object $update, array $options = []): MongoDB\UpdateResult
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBDatabase-command.txt b/docs/reference/method/MongoDBDatabase-command.txt
index d442541cf..6853daad8 100644
--- a/docs/reference/method/MongoDBDatabase-command.txt
+++ b/docs/reference/method/MongoDBDatabase-command.txt
@@ -21,7 +21,7 @@ Definition
 
    .. code-block:: php
 
-      function command($command, array $options = []): MongoDB\Driver\Cursor
+      function command(array|object $command, array $options = []): MongoDB\Driver\Cursor
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBDatabase-createCollection.txt b/docs/reference/method/MongoDBDatabase-createCollection.txt
index d640f3d19..758ad6c2a 100644
--- a/docs/reference/method/MongoDBDatabase-createCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-createCollection.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function createCollection($collectionName, array $options = []): array|object
+      function createCollection(string $collectionName, array $options = []): array|object
 
    MongoDB creates collections implicitly when you first reference the
    collection in a command, such as when inserting a document into a new
diff --git a/docs/reference/method/MongoDBDatabase-dropCollection.txt b/docs/reference/method/MongoDBDatabase-dropCollection.txt
index 2b58785aa..028e63f00 100644
--- a/docs/reference/method/MongoDBDatabase-dropCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-dropCollection.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function dropCollection($collectionName, array $options = []): array|object
+      function dropCollection(string $collectionName, array $options = []): array|object
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBDatabase-modifyCollection.txt b/docs/reference/method/MongoDBDatabase-modifyCollection.txt
index 8fe9245c6..86c1ff523 100644
--- a/docs/reference/method/MongoDBDatabase-modifyCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-modifyCollection.txt
@@ -22,7 +22,7 @@ Definition
 
    .. code-block:: php
 
-      function modifyCollection($collectionName, array $collectionOptions, array $options = []): array|object
+      function modifyCollection(string $collectionName, array $collectionOptions, array $options = []): array|object
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBDatabase-selectCollection.txt b/docs/reference/method/MongoDBDatabase-selectCollection.txt
index fb17687b4..148854100 100644
--- a/docs/reference/method/MongoDBDatabase-selectCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-selectCollection.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function selectCollection($collectionName, array $options = []): MongoDB\Collection
+      function selectCollection(string $collectionName, array $options = []): MongoDB\Collection
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBDatabase__get.txt b/docs/reference/method/MongoDBDatabase__get.txt
index 280e931da..53cef6f9d 100644
--- a/docs/reference/method/MongoDBDatabase__get.txt
+++ b/docs/reference/method/MongoDBDatabase__get.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function __get($collectionName): MongoDB\Collection
+      function __get(string $collectionName): MongoDB\Collection
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt b/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt
index a37134a4a..acc236f57 100644
--- a/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-downloadToStreamByName.txt
@@ -20,7 +20,7 @@ Definition
 
    .. code-block:: php
 
-      function downloadToStreamByName(string $filename, $destination, array $options = []): void
+      function downloadToStreamByName(string $filename, resource $destination, array $options = []): void
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBGridFSBucket-find.txt b/docs/reference/method/MongoDBGridFSBucket-find.txt
index 6b3c7728b..e0a4e6621 100644
--- a/docs/reference/method/MongoDBGridFSBucket-find.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-find.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function find($filter = [], array $options = []): MongoDB\Driver\Cursor
+      function find(array|object $filter = [], array $options = []): MongoDB\Driver\Cursor
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBGridFSBucket-findOne.txt b/docs/reference/method/MongoDBGridFSBucket-findOne.txt
index a72de457e..f126448d9 100644
--- a/docs/reference/method/MongoDBGridFSBucket-findOne.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-findOne.txt
@@ -20,7 +20,7 @@ Definition
 
    .. code-block:: php
 
-      function findOne($filter = [], array $options = []): array|object|null
+      function findOne(array|object $filter = [], array $options = []): array|object|null
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt b/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt
index b9dca55ad..f8d633ed2 100644
--- a/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-getFileDocumentForStream.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function getFileDocumentForStream($stream): array|object
+      function getFileDocumentForStream(resource $stream): array|object
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt b/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt
index 4e1c68b48..f88dc885a 100644
--- a/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-getFileIdForStream.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function getFileIdForStream($stream): mixed
+      function getFileIdForStream(resource $stream): mixed
 
    This method has the following parameters:
 
diff --git a/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt b/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt
index 2487554dd..18e5944b6 100644
--- a/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt
+++ b/docs/reference/method/MongoDBGridFSBucket-uploadFromStream.txt
@@ -19,7 +19,7 @@ Definition
 
    .. code-block:: php
 
-      function uploadFromStream(string $filename, $source, array $options = []): mixed
+      function uploadFromStream(string $filename, resource $source, array $options = []): mixed
 
    This method has the following parameters:
 

From 3bd3fb450a9df1eed6d4c73fa6061771d77c5edc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Fri, 26 May 2023 09:34:34 +0200
Subject: [PATCH 286/321] PHPLIB-1135: Remove var_dump from tests, use print_r
 instead (#1081)

* Remove var_dump from tests
* psalm-suppress no longer necessary

var_dump output is modified by xdebug, leading to test failure during debug
---
 examples/persistable.php |   5 +-
 examples/typemap.php     |   5 +-
 tests/ExamplesTest.php   | 102 +++++++++++++++++++--------------------
 3 files changed, 54 insertions(+), 58 deletions(-)

diff --git a/examples/persistable.php b/examples/persistable.php
index e4a5c95e9..6e23a16bb 100644
--- a/examples/persistable.php
+++ b/examples/persistable.php
@@ -10,7 +10,7 @@
 use UnexpectedValueException;
 
 use function getenv;
-use function var_dump;
+use function print_r;
 
 require __DIR__ . '/../vendor/autoload.php';
 
@@ -105,5 +105,4 @@ public function bsonUnserialize(array $data): void
 
 $foundEntry = $collection->findOne([]);
 
-/** @psalm-suppress ForbiddenCode */
-var_dump($foundEntry);
+print_r($foundEntry);
diff --git a/examples/typemap.php b/examples/typemap.php
index 51097bc90..9dc96b016 100644
--- a/examples/typemap.php
+++ b/examples/typemap.php
@@ -10,7 +10,7 @@
 
 use function getenv;
 use function is_array;
-use function var_dump;
+use function print_r;
 
 require __DIR__ . '/../vendor/autoload.php';
 
@@ -116,5 +116,4 @@ public function bsonUnserialize(array $data): void
 
 $entry = $collection->findOne([], ['typeMap' => $typeMap]);
 
-/** @psalm-suppress ForbiddenCode */
-var_dump($entry);
+print_r($entry);
diff --git a/tests/ExamplesTest.php b/tests/ExamplesTest.php
index 79747533a..997bc3312 100644
--- a/tests/ExamplesTest.php
+++ b/tests/ExamplesTest.php
@@ -90,32 +90,31 @@ public function dataExamples(): Generator
         ];
 
         $expectedOutput = <<<'OUTPUT'
-object(MongoDB\Examples\PersistableEntry)#%d (%d) {
-  ["id":"MongoDB\Examples\PersistableEntry":private]=>
-  object(MongoDB\BSON\ObjectId)#%d (%d) {
-    ["oid"]=>
-    string(24) "%s"
-  }
-  ["name"]=>
-  string(7) "alcaeus"
-  ["emails"]=>
-  array(2) {
-    [0]=>
-    object(MongoDB\Examples\PersistableEmail)#%d (%d) {
-      ["type"]=>
-      string(4) "work"
-      ["address"]=>
-      string(19) "alcaeus@example.com"
-    }
-    [1]=>
-    object(MongoDB\Examples\PersistableEmail)#%d (%d) {
-      ["type"]=>
-      string(7) "private"
-      ["address"]=>
-      string(18) "secret@example.com"
-    }
-  }
-}
+MongoDB\Examples\PersistableEntry Object
+(
+    [id:MongoDB\Examples\PersistableEntry:private] => MongoDB\BSON\ObjectId Object
+        (
+            [oid] => %s
+        )
+
+    [name] => alcaeus
+    [emails] => Array
+        (
+            [0] => MongoDB\Examples\PersistableEmail Object
+                (
+                    [type] => work
+                    [address] => alcaeus@example.com
+                )
+
+            [1] => MongoDB\Examples\PersistableEmail Object
+                (
+                    [type] => private
+                    [address] => secret@example.com
+                )
+
+        )
+
+)
 OUTPUT;
 
         yield 'persistable' => [
@@ -124,32 +123,31 @@ public function dataExamples(): Generator
         ];
 
         $expectedOutput = <<<'OUTPUT'
-object(MongoDB\Examples\TypeMapEntry)#%d (%d) {
-  ["id":"MongoDB\Examples\TypeMapEntry":private]=>
-  object(MongoDB\BSON\ObjectId)#%d (%d) {
-    ["oid"]=>
-    string(24) "%s"
-  }
-  ["name":"MongoDB\Examples\TypeMapEntry":private]=>
-  string(7) "alcaeus"
-  ["emails":"MongoDB\Examples\TypeMapEntry":private]=>
-  array(2) {
-    [0]=>
-    object(MongoDB\Examples\TypeMapEmail)#%d (%d) {
-      ["type":"MongoDB\Examples\TypeMapEmail":private]=>
-      string(4) "work"
-      ["address":"MongoDB\Examples\TypeMapEmail":private]=>
-      string(19) "alcaeus@example.com"
-    }
-    [1]=>
-    object(MongoDB\Examples\TypeMapEmail)#%d (%d) {
-      ["type":"MongoDB\Examples\TypeMapEmail":private]=>
-      string(7) "private"
-      ["address":"MongoDB\Examples\TypeMapEmail":private]=>
-      string(18) "secret@example.com"
-    }
-  }
-}
+MongoDB\Examples\TypeMapEntry Object
+(
+    [id:MongoDB\Examples\TypeMapEntry:private] => MongoDB\BSON\ObjectId Object
+        (
+            [oid] => %s
+        )
+
+    [name:MongoDB\Examples\TypeMapEntry:private] => alcaeus
+    [emails:MongoDB\Examples\TypeMapEntry:private] => Array
+        (
+            [0] => MongoDB\Examples\TypeMapEmail Object
+                (
+                    [type:MongoDB\Examples\TypeMapEmail:private] => work
+                    [address:MongoDB\Examples\TypeMapEmail:private] => alcaeus@example.com
+                )
+
+            [1] => MongoDB\Examples\TypeMapEmail Object
+                (
+                    [type:MongoDB\Examples\TypeMapEmail:private] => private
+                    [address:MongoDB\Examples\TypeMapEmail:private] => secret@example.com
+                )
+
+        )
+
+)
 OUTPUT;
 
         yield 'typemap' => [

From 8d985e6c2a470322c4af2e7c7a7602729ff7bcf6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Fri, 26 May 2023 09:59:09 +0200
Subject: [PATCH 287/321] Remove unreachable code (#1079)

---
 src/GridFS/StreamWrapper.php  | 4 ----
 src/GridFS/WritableStream.php | 5 +----
 src/Operation/Explain.php     | 9 ---------
 3 files changed, 1 insertion(+), 17 deletions(-)

diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php
index 3e04c3d14..a90104e9a 100644
--- a/src/GridFS/StreamWrapper.php
+++ b/src/GridFS/StreamWrapper.php
@@ -46,9 +46,6 @@ class StreamWrapper
     /** @var resource|null Stream context (set by PHP) */
     public $context;
 
-    /** @var string|null */
-    private $mode;
-
     /** @var string|null */
     private $protocol;
 
@@ -127,7 +124,6 @@ public function stream_eof(): bool
     public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool
     {
         $this->initProtocol($path);
-        $this->mode = $mode;
 
         if ($mode === 'r') {
             return $this->initReadableStream();
diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php
index 73f5b44cc..dd2963fda 100644
--- a/src/GridFS/WritableStream.php
+++ b/src/GridFS/WritableStream.php
@@ -255,8 +255,7 @@ private function abort(): void
         $this->isClosed = true;
     }
 
-    /** @return mixed */
-    private function fileCollectionInsert()
+    private function fileCollectionInsert(): void
     {
         $this->file['length'] = $this->length;
         $this->file['uploadDate'] = new UTCDateTime();
@@ -272,8 +271,6 @@ private function fileCollectionInsert()
 
             throw $e;
         }
-
-        return $this->file['_id'];
     }
 
     private function insertChunkFromBuffer(): void
diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php
index 13ae85d09..cc59670e4 100644
--- a/src/Operation/Explain.php
+++ b/src/Operation/Explain.php
@@ -159,13 +159,4 @@ private function createOptions(): array
 
         return $options;
     }
-
-    private function isFindAndModify(Explainable $explainable): bool
-    {
-        if ($explainable instanceof FindAndModify || $explainable instanceof FindOneAndDelete || $explainable instanceof FindOneAndReplace || $explainable instanceof FindOneAndUpdate) {
-            return true;
-        }
-
-        return false;
-    }
 }

From 789368ada4f63e79c492bdc0a94ae1126cf02826 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Fri, 26 May 2023 19:12:56 +0800
Subject: [PATCH 288/321] PHPLIB-1122: Support Document and PackedArray objects
 in public APIs (#1077)

Excluding tests, most changes were concentrated in functions.php. A document_to_array() function was introduced to make it easier to access document values as arrays. This is mainly used by other utility functions (e.g. checking for dollar prefixed keys) but also ended up being used in the Find operation for handling the "modifiers" option.

Adds tests for using Document and PackedArray objects in operations.

Beyond handling of document/array types, this also filled gaps in test coverage for:

 * Validation for IndexInput key/name options
 * Passing a MongoDB\Driver\Command directly to DatabaseCommand
 * is_last_pipeline_operator_write()

* Use elseif for checking Serializable after Document or PackedArray

Processing a Document and PackedArray will yield an array, so we can avoid a redundant Serializable check by using elseif.

* Use array_key_first() and refactor is_pipeline() to use is_first_key_operator()

This introduces a dependency on symfony/polyfill-php73 and bumps both polyfill packages to the latest minor version for consistency.

The doc block for is_first_key_operator() was revised to note its additional purpose for validating pipeline stages.

* Test is_first_key_operator() with empty and packed arrays

* Note an edge case where is_pipeline() may throw InvalidArgumentException

* Add type annotations to assist static analysis

* Use psalm-var annotation and fix phpcs errors

* Regenerate psalm baseline

This suppresses a new error in BulkWrite pertaining to a variable previously checked by is_first_key_operator() and is_pipeline().

```
ERROR: MixedArgument - src/Operation/BulkWrite.php:341:45 - Argument 2 of MongoDB\Driver\BulkWrite::update cannot be mixed, expecting array|object (see https://psalm.dev/030)
                    $bulk->update($args[0], $args[1], $args[2]);

  The type of $args[1] is sourced from here - vendor/vimeo/psalm/stubs/CoreGenericFunctions.phpstub:154:12
 * @return (TArray is array ? false : (TArray is non-empty-array ? TValue : TValue|false))
```

Other changes to the baseline are removals for obsolete errors.
---
 composer.json                                 |   3 +-
 psalm-baseline.xml                            |  96 +---------
 src/Operation/Find.php                        |   9 +-
 src/Operation/FindAndModify.php               |   6 +-
 src/functions.php                             | 126 ++++++++-----
 tests/FunctionsTest.php                       | 171 +++++++++++++-----
 .../CountDocumentsFunctionalTest.php          |  35 ++++
 tests/Operation/CountFunctionalTest.php       |  34 ++++
 .../Operation/CreateIndexesFunctionalTest.php |  27 ++-
 tests/Operation/CreateIndexesTest.php         |  52 ++++++
 .../DatabaseCommandFunctionalTest.php         |  35 ++++
 tests/Operation/DeleteFunctionalTest.php      |  35 ++++
 tests/Operation/DistinctFunctionalTest.php    |  35 ++++
 .../Operation/FindAndModifyFunctionalTest.php |  96 ++++++++++
 tests/Operation/FindFunctionalTest.php        |  66 +++++++
 tests/Operation/FindOneAndReplaceTest.php     |  26 ++-
 tests/Operation/FindOneAndUpdateTest.php      |  22 ++-
 tests/Operation/InsertManyFunctionalTest.php  |  89 +++++++--
 tests/Operation/InsertOneFunctionalTest.php   |  83 ++++++---
 tests/Operation/ReplaceOneTest.php            |  39 ++--
 tests/Operation/UpdateFunctionalTest.php      | 101 +++++++++++
 tests/Operation/UpdateManyTest.php            |  41 +++--
 tests/Operation/UpdateOneTest.php             |  41 +++--
 tests/Operation/UpdateTest.php                |  25 +++
 tests/TestCase.php                            |   1 +
 25 files changed, 1017 insertions(+), 277 deletions(-)

diff --git a/composer.json b/composer.json
index 7540bd0da..e9ee7edae 100644
--- a/composer.json
+++ b/composer.json
@@ -14,7 +14,8 @@
         "ext-json": "*",
         "ext-mongodb": "^1.16.0",
         "jean85/pretty-package-versions": "^2.0.1",
-        "symfony/polyfill-php80": "^1.19"
+        "symfony/polyfill-php73": "^1.27",
+        "symfony/polyfill-php80": "^1.27"
     },
     "require-dev": {
         "squizlabs/php_codesniffer": "^3.7",
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 96bc27919..583e0c94d 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -1,37 +1,5 @@
 
 
-  
-    
-      string
-    
-    
-      toRelaxedExtendedJSON(fromPHP($document))
-    
-  
-  
-    
-      string
-    
-    
-      toRelaxedExtendedJSON(fromPHP($document))
-    
-  
-  
-    
-      string
-    
-    
-      toRelaxedExtendedJSON(fromPHP($document))
-    
-  
-  
-    
-      string
-    
-    
-      toRelaxedExtendedJSON(fromPHP($document))
-    
-  
   
     
       $address
@@ -41,14 +9,6 @@
       $type
     
   
-  
-    
-      string
-    
-    
-      toRelaxedExtendedJSON(fromPHP($document))
-    
-  
   
     
       $driverOptions['driver'] ?? []
@@ -57,16 +17,6 @@
       $mergedDriver['platform']
     
   
-  
-    
-      $encryptedFields['eccCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecc'
-      $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $this->collectionName . '.ecoc'
-      $encryptedFields['escCollection'] ?? 'enxcol_.' . $this->collectionName . '.esc'
-    
-    
-      $encryptedFields
-    
-  
   
     
       $cmd[$option]
@@ -79,21 +29,6 @@
       $options['session']
     
   
-  
-    
-      $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'
-      $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'
-      $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'
-      $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'
-      $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'
-      $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'
-    
-    
-      $encryptedFields
-      $encryptedFields
-      $options['encryptedFields']
-    
-  
   
     
       new static(sprintf('%s is immutable', $class))
@@ -139,14 +74,10 @@
       drop
       rename
     
-    
-      $id
+    
       $options['revision']
       $options['revision']
     
-    
-      $id
-    
   
   
     
@@ -157,24 +88,12 @@
     
   
   
-    
-      $json
-    
-    
-      $json
-    
     
       new static(sprintf('File "%s" not found in "%s"', $json, $namespace))
       new static(sprintf('File with name "%s" and revision "%d" not found in "%s"', $filename, $revision, $namespace))
     
   
   
-    
-      $idString
-    
-    
-      $idString
-    
     
       new static(sprintf('Downloading file from "%s" to "%s" failed. GridFS filename: "%s"', $sourceMetadata['uri'], $destinationMetadata['uri'], $filename))
       new static(sprintf('Downloading file from "%s" to "%s" failed. GridFS identifier: "%s"', $sourceMetadata['uri'], $destinationMetadata['uri'], $idString))
@@ -384,7 +303,7 @@
     
       is_array($operation)
     
-    
+    
       $args
       $args
       $args
@@ -395,6 +314,7 @@
       $args[1]
       $args[1]
       $args[1]
+      $args[1]
       $args[2]
     
     
@@ -629,10 +549,9 @@
       $this->options['typeMap']
       $this->options['writeConcern']
     
-    
+    
       $cmd[$option]
       $cmd['new']
-      $cmd['update']
       $cmd['upsert']
       $options['session']
       $options['writeConcern']
@@ -834,11 +753,9 @@
     
   
   
-    
+    
       ! is_array($document) && ! is_object($document)
       is_array($document)
-      is_array($document)
-      is_array($out)
     
     
       $wireVersionForWriteStageOnSecondary
@@ -853,9 +770,8 @@
       $typeMap['fieldPaths'][$fieldPath]
       $typeMap['fieldPaths'][substr($fieldPath, 0, -2)]
     
-    
+    
       $element[$key]
-      $lastOp
       $type
       $type
       $typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath]
diff --git a/src/Operation/Find.php b/src/Operation/Find.php
index 619e6f5c5..8f1e56f49 100644
--- a/src/Operation/Find.php
+++ b/src/Operation/Find.php
@@ -32,6 +32,7 @@
 use function is_integer;
 use function is_object;
 use function is_string;
+use function MongoDB\document_to_array;
 use function trigger_error;
 
 use const E_USER_DEPRECATED;
@@ -427,10 +428,10 @@ private function createQueryOptions(): array
             }
         }
 
-        $modifiers = empty($this->options['modifiers']) ? [] : (array) $this->options['modifiers'];
-
-        if (! empty($modifiers)) {
-            $options['modifiers'] = $modifiers;
+        if (! empty($this->options['modifiers'])) {
+            /** @psalm-var array|object */
+            $modifiers = $this->options['modifiers'];
+            $options['modifiers'] = is_object($modifiers) ? document_to_array($modifiers) : $modifiers;
         }
 
         return $options;
diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php
index d4fc2b3a4..cb97637f7 100644
--- a/src/Operation/FindAndModify.php
+++ b/src/Operation/FindAndModify.php
@@ -293,9 +293,9 @@ private function createCommandDocument(): array
         }
 
         if (isset($this->options['update'])) {
-            $cmd['update'] = is_pipeline($this->options['update'])
-                ? $this->options['update']
-                : (object) $this->options['update'];
+            /** @psalm-var array|object */
+            $update = $this->options['update'];
+            $cmd['update'] = is_pipeline($update) ? $update : (object) $update;
         }
 
         foreach (['arrayFilters', 'bypassDocumentValidation', 'comment', 'hint', 'maxTimeMS'] as $option) {
diff --git a/src/functions.php b/src/functions.php
index 412ef7a58..8a5f8e880 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -18,6 +18,8 @@
 namespace MongoDB;
 
 use Exception;
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\BSON\Serializable;
 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
 use MongoDB\Driver\Manager;
@@ -32,10 +34,10 @@
 use ReflectionClass;
 use ReflectionException;
 
+use function array_key_first;
 use function assert;
 use function end;
 use function get_object_vars;
-use function in_array;
 use function is_array;
 use function is_object;
 use function is_string;
@@ -94,20 +96,40 @@ function apply_type_map_to_document($document, array $typeMap)
 }
 
 /**
- * Generate an index name from a key specification.
+ * Converts a document parameter to an array.
+ *
+ * This is used to facilitate unified access to document fields. It also handles
+ * Document, PackedArray, and Serializable objects.
+ *
+ * This function is not used for type checking. Therefore, it does not reject
+ * PackedArray objects or Serializable::bsonSerialize() return values that would
+ * encode as BSON arrays.
  *
  * @internal
- * @param array|object $document Document containing fields mapped to values,
- *                               which denote order or an index type
- * @throws InvalidArgumentException
+ * @param array|object $document
+ * @throws InvalidArgumentException if $document is not an array or object
  */
-function generate_index_name($document): string
+function document_to_array($document): array
 {
-    if ($document instanceof Serializable) {
+    if ($document instanceof Document || $document instanceof PackedArray) {
+        /* Nested documents and arrays are intentionally left as BSON. We avoid
+         * iterator_to_array() since Document and PackedArray iteration returns
+         * all values as MongoDB\BSON\Value instances. */
+
+        /** @psalm-var array */
+        return $document->toPHP([
+            'array' => 'bson',
+            'document' => 'bson',
+            'root' => 'array',
+        ]);
+    } elseif ($document instanceof Serializable) {
         $document = $document->bsonSerialize();
     }
 
     if (is_object($document)) {
+        /* Note: this omits all uninitialized properties, whereas BSON encoding
+         * includes untyped, uninitialized properties. This is acceptable given
+         * document_to_array()'s use cases. */
         $document = get_object_vars($document);
     }
 
@@ -115,6 +137,21 @@ function generate_index_name($document): string
         throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
     }
 
+    return $document;
+}
+
+/**
+ * Generate an index name from a key specification.
+ *
+ * @internal
+ * @param array|object $document Document containing fields mapped to values,
+ *                               which denote order or an index type
+ * @throws InvalidArgumentException if $document is not an array or object
+ */
+function generate_index_name($document): string
+{
+    $document = document_to_array($document);
+
     $name = '';
 
     foreach ($document as $field => $type) {
@@ -174,40 +211,55 @@ function get_encrypted_fields_from_server(string $databaseName, string $collecti
 /**
  * Return whether the first key in the document starts with a "$" character.
  *
- * This is used for differentiating update and replacement documents.
+ * This is used for validating aggregation pipeline stages and differentiating
+ * update and replacement documents. Since true and false return values may be
+ * expected in different contexts, this function intentionally throws if
+ * $document has an unexpected type instead of returning false.
  *
  * @internal
- * @param array|object $document Update or replacement document
- * @throws InvalidArgumentException
+ * @param array|object $document
+ * @throws InvalidArgumentException if $document is not an array or object
  */
 function is_first_key_operator($document): bool
 {
-    if ($document instanceof Serializable) {
-        $document = $document->bsonSerialize();
-    }
+    $document = document_to_array($document);
 
-    if (is_object($document)) {
-        $document = get_object_vars($document);
-    }
+    $firstKey = array_key_first($document);
 
-    if (! is_array($document)) {
-        throw InvalidArgumentException::invalidType('$document', $document, 'array or object');
+    if (! is_string($firstKey)) {
+        return false;
     }
 
-    reset($document);
-    $firstKey = (string) key($document);
-
-    return isset($firstKey[0]) && $firstKey[0] === '$';
+    return '$' === ($firstKey[0] ?? null);
 }
 
 /**
  * Returns whether an update specification is a valid aggregation pipeline.
  *
+ * Note: this method may propagate an InvalidArgumentException from
+ * document_or_array() if a Serializable object within the pipeline array
+ * returns a non-array, non-object value from its bsonSerialize() method.
+ *
  * @internal
- * @param mixed $pipeline
+ * @param array|object $pipeline
+ * @throws InvalidArgumentException
  */
 function is_pipeline($pipeline): bool
 {
+    if ($pipeline instanceof PackedArray) {
+        /* Nested documents and arrays are intentionally left as BSON. We avoid
+         * iterator_to_array() since Document iteration returns all values as
+         * MongoDB\BSON\Value instances. */
+        /** @psalm-var array */
+        $pipeline = $pipeline->toPHP([
+            'array' => 'bson',
+            'document' => 'bson',
+            'root' => 'array',
+        ]);
+    } elseif ($pipeline instanceof Serializable) {
+        $pipeline = $pipeline->bsonSerialize();
+    }
+
     if (! is_array($pipeline)) {
         return false;
     }
@@ -228,11 +280,8 @@ function is_pipeline($pipeline): bool
         }
 
         $expectedKey++;
-        $stage = (array) $stage;
-        reset($stage);
-        $key = key($stage);
 
-        if (! is_string($key) || substr($key, 0, 1) !== '$') {
+        if (! is_first_key_operator($stage)) {
             return false;
         }
     }
@@ -272,9 +321,15 @@ function is_last_pipeline_operator_write(array $pipeline): bool
         return false;
     }
 
-    $lastOp = (array) $lastOp;
+    if (! is_array($lastOp) && ! is_object($lastOp)) {
+        return false;
+    }
+
+    $lastOp = document_to_array($lastOp);
 
-    return in_array(key($lastOp), ['$out', '$merge'], true);
+    reset($lastOp);
+
+    return key($lastOp) === '$merge' || key($lastOp) === '$out';
 }
 
 /**
@@ -285,7 +340,6 @@ function is_last_pipeline_operator_write(array $pipeline): bool
  * @internal
  * @see https://mongodb.com/docs/manual/reference/command/mapReduce/#output-inline
  * @param string|array|object $out Output specification
- * @throws InvalidArgumentException
  */
 function is_mapreduce_output_inline($out): bool
 {
@@ -293,17 +347,7 @@ function is_mapreduce_output_inline($out): bool
         return false;
     }
 
-    if ($out instanceof Serializable) {
-        $out = $out->bsonSerialize();
-    }
-
-    if (is_object($out)) {
-        $out = get_object_vars($out);
-    }
-
-    if (! is_array($out)) {
-        throw InvalidArgumentException::invalidType('$out', $out, 'array or object');
-    }
+    $out = document_to_array($out);
 
     reset($out);
 
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index 6983313ac..167cbe291 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -2,6 +2,8 @@
 
 namespace MongoDB\Tests;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Model\BSONArray;
@@ -9,8 +11,10 @@
 
 use function MongoDB\apply_type_map_to_document;
 use function MongoDB\create_field_path_type_map;
+use function MongoDB\document_to_array;
 use function MongoDB\generate_index_name;
 use function MongoDB\is_first_key_operator;
+use function MongoDB\is_last_pipeline_operator_write;
 use function MongoDB\is_mapreduce_output_inline;
 use function MongoDB\is_pipeline;
 use function MongoDB\is_write_concern_acknowledged;
@@ -90,46 +94,71 @@ public function provideDocumentAndTypeMap()
         ];
     }
 
-    /** @dataProvider provideIndexSpecificationDocumentsAndGeneratedNames */
-    public function testGenerateIndexName($document, $expectedName): void
+    /** @dataProvider provideDocumentsAndExpectedArrays */
+    public function testDocumentToArray($document, array $expectedArray): void
     {
-        $this->assertSame($expectedName, generate_index_name($document));
+        $this->assertSame($expectedArray, document_to_array($document));
     }
 
-    public function provideIndexSpecificationDocumentsAndGeneratedNames()
+    public function provideDocumentsAndExpectedArrays(): array
     {
         return [
-            [ ['x' => 1], 'x_1' ],
-            [ ['x' => -1, 'y' => 1], 'x_-1_y_1' ],
-            [ ['x' => '2dsphere', 'y' => 1 ], 'x_2dsphere_y_1' ],
-            [ (object) ['x' => 1], 'x_1' ],
-            [ new BSONDocument(['x' => 1]), 'x_1' ],
+            'array' => [['x' => 1], ['x' => 1]],
+            'object' => [(object) ['x' => 1], ['x' => 1]],
+            'Serializable' => [new BSONDocument(['x' => 1]), ['x' => 1]],
+            'Document' => [Document::fromPHP(['x' => 1]), ['x' => 1]],
+            // PackedArray and array-returning Serializable are both allowed
+            'PackedArray' => [PackedArray::fromPHP(['foo']), [0 => 'foo']],
+            'Serializable:array' => [new BSONArray(['foo']), [0 => 'foo']],
         ];
     }
 
     /** @dataProvider provideInvalidDocumentValues */
-    public function testGenerateIndexNameArgumentTypeCheck($document): void
+    public function testDocumentToArrayArgumentTypeCheck($document): void
     {
         $this->expectException(InvalidArgumentException::class);
-        generate_index_name($document);
+        $this->expectExceptionMessage('Expected $document to have type "array or object"');
+        document_to_array($document);
     }
 
-    /** @dataProvider provideIsFirstKeyOperatorDocuments */
-    public function testIsFirstKeyOperator($document, $isFirstKeyOperator): void
+    /** @dataProvider provideDocumentCasts */
+    public function testGenerateIndexName($cast): void
     {
-        $this->assertSame($isFirstKeyOperator, is_first_key_operator($document));
+        $this->assertSame('x_1', generate_index_name($cast(['x' => 1])));
+        $this->assertSame('x_-1_y_1', generate_index_name($cast(['x' => -1, 'y' => 1])));
+        $this->assertSame('x_2dsphere_y_1', generate_index_name($cast(['x' => '2dsphere', 'y' => 1])));
     }
 
-    public function provideIsFirstKeyOperatorDocuments()
+    public function provideDocumentCasts(): array
     {
+        // phpcs:disable SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing
+        // phpcs:disable Squiz.Functions.MultiLineFunctionDeclaration
+        // phpcs:disable Squiz.WhiteSpace.ScopeClosingBrace.ContentBefore
         return [
-            [ ['y' => 1], false ],
-            [ (object) ['y' => 1], false ],
-            [ new BSONDocument(['y' => 1]), false ],
-            [ ['$set' => ['y' => 1]], true ],
-            [ (object) ['$set' => ['y' => 1]], true ],
-            [ new BSONDocument(['$set' => ['y' => 1]]), true ],
+            'array' => [function ($value) { return $value; }],
+            'object' => [function ($value) { return (object) $value; }],
+            'Serializable' => [function ($value) { return new BSONDocument($value); }],
+            'Document' => [function ($value) { return Document::fromPHP($value); }],
         ];
+        // phpcs:enable
+    }
+
+    /** @dataProvider provideInvalidDocumentValues */
+    public function testGenerateIndexNameArgumentTypeCheck($document): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        generate_index_name($document);
+    }
+
+    /** @dataProvider provideDocumentCasts */
+    public function testIsFirstKeyOperator(callable $cast): void
+    {
+        $this->assertFalse(is_first_key_operator($cast(['y' => 1])));
+        $this->assertTrue(is_first_key_operator($cast(['$set' => ['y' => 1]])));
+
+        // Empty and packed arrays are unlikely arguments, but still valid
+        $this->assertFalse(is_first_key_operator($cast([])));
+        $this->assertFalse(is_first_key_operator($cast(['foo'])));
     }
 
     /** @dataProvider provideInvalidDocumentValues */
@@ -139,20 +168,18 @@ public function testIsFirstKeyOperatorArgumentTypeCheck($document): void
         is_first_key_operator($document);
     }
 
-    /** @dataProvider provideMapReduceOutValues */
-    public function testIsMapReduceOutputInline($out, $isInline): void
+    /** @dataProvider provideDocumentCasts */
+    public function testIsMapReduceOutputInlineWithDocumentValues(callable $cast): void
     {
-        $this->assertSame($isInline, is_mapreduce_output_inline($out));
+        $this->assertTrue(is_mapreduce_output_inline($cast(['inline' => 1])));
+        // Note: only the key is significant
+        $this->assertTrue(is_mapreduce_output_inline($cast(['inline' => 0])));
+        $this->assertFalse(is_mapreduce_output_inline($cast(['replace' => 'collectionName'])));
     }
 
-    public function provideMapReduceOutValues()
+    public function testIsMapReduceOutputInlineWithStringValue(): void
     {
-        return [
-            [ 'collectionName', false ],
-            [ ['inline' => 1], true ],
-            [ ['inline' => 0], true ], // only the key is significant
-            [ ['replace' => 'collectionName'], false ],
-        ];
+        $this->assertFalse(is_mapreduce_output_inline('collectionName'));
     }
 
     /** @dataProvider provideTypeMapValues */
@@ -215,30 +242,80 @@ public function provideTypeMapValues()
         ];
     }
 
+    /** @dataProvider provideDocumentCasts */
+    public function testIsLastPipelineOperatorWrite(callable $cast): void
+    {
+        $match = ['$match' => ['x' => 1]];
+        $merge = ['$merge' => ['into' => 'coll']];
+        $out = ['$out' => ['db' => 'db', 'coll' => 'coll']];
+
+        $this->assertTrue(is_last_pipeline_operator_write([$cast($merge)]));
+        $this->assertTrue(is_last_pipeline_operator_write([$cast($out)]));
+        $this->assertTrue(is_last_pipeline_operator_write([$cast($match), $cast($merge)]));
+        $this->assertTrue(is_last_pipeline_operator_write([$cast($match), $cast($out)]));
+        $this->assertFalse(is_last_pipeline_operator_write([$cast($match)]));
+        $this->assertFalse(is_last_pipeline_operator_write([$cast($merge), $cast($match)]));
+        $this->assertFalse(is_last_pipeline_operator_write([$cast($out), $cast($match)]));
+    }
+
     /** @dataProvider providePipelines */
     public function testIsPipeline($expected, $pipeline): void
     {
         $this->assertSame($expected, is_pipeline($pipeline));
     }
 
-    public function providePipelines()
+    public function providePipelines(): array
     {
+        $valid = [
+            ['$match' => ['foo' => 'bar']],
+            (object) ['$group' => ['_id' => 1]],
+            new BSONDocument(['$skip' => 1]),
+            Document::fromPHP(['$limit' => 1]),
+        ];
+
+        $invalidIndex = [1 => ['$group' => ['_id' => 1]]];
+
+        $invalidStageKey = [['group' => ['_id' => 1]]];
+
+        $dbrefInNumericField = ['0' => ['$ref' => 'foo', '$id' => 'bar']];
+
         return [
-            'Not an array' => [false, (object) []],
-            'Empty array' => [false, []],
-            'Non-sequential indexes in array' => [false, [1 => ['$group' => []]]],
-            'Update document instead of pipeline' => [false, ['$set' => ['foo' => 'bar']]],
-            'Invalid pipeline stage' => [false, [['group' => []]]],
-            'Update with DbRef' => [false, ['x' => ['$ref' => 'foo', '$id' => 'bar']]],
-            'Valid pipeline' => [
-                true,
-                [
-                    ['$match' => ['foo' => 'bar']],
-                    ['$group' => ['_id' => 1]],
-                ],
-            ],
-            'False positive with DbRef in numeric field' => [true, ['0' => ['$ref' => 'foo', '$id' => 'bar']]],
-            'DbRef in numeric field as object' => [false, (object) ['0' => ['$ref' => 'foo', '$id' => 'bar']]],
+            // Valid pipeline in various forms
+            'valid: array' => [true, $valid],
+            'valid: Serializable' => [true, new BSONArray($valid)],
+            'valid: PackedArray' => [true, PackedArray::fromPHP($valid)],
+            // Invalid type for an otherwise valid pipeline
+            'invalid type: stdClass' => [false, (object) $valid],
+            'invalid type: Serializable' => [false, new BSONDocument($valid)],
+            'invalid type: Document' => [false, Document::fromPHP($valid)],
+            // Invalid index in pipeline array
+            'invalid index: array' => [false, $invalidIndex],
+            // Note: PackedArray::fromPHP() requires a list array
+            // Note: BSONArray::bsonSerialize() re-indexes the array
+            'invalid index: array' => [true, new BSONArray($invalidIndex)],
+            // Invalid stage key in pipeline element
+            'invalid stage key: array' => [false, $invalidStageKey],
+            'invalid stage key: Serializable' => [false, new BSONArray($invalidStageKey)],
+            'invalid stage key: PackedArray' => [false, PackedArray::fromPHP($invalidStageKey)],
+            // Invalid pipeline element type
+            'invalid pipeline element type: array' => [false, [[[]]]],
+            'invalid pipeline element type: Serializable' => [false, new BSONArray([new BSONArray([])])],
+            'invalid pipeline element type: PackedArray' => [false, PackedArray::fromPHP([[]])],
+            // Empty array has no pipeline stages
+            'invalid empty: array' => [false, []],
+            'invalid empty: Serializable' => [false, new BSONArray([])],
+            'invalid empty: PackedArray' => [false, PackedArray::fromPHP([])],
+            // False positive: DBRef in numeric field
+            'false positive DBRef: array' => [true, $dbrefInNumericField],
+            'false positive DBRef: Serializable' => [true, new BSONArray($dbrefInNumericField)],
+            'false positive DBRef: PackedArray' => [true, PackedArray::fromPHP($dbrefInNumericField)],
+            // Invalid document containing DBRef in numeric field
+            'invalid DBRef: stdClass' => [false, (object) $dbrefInNumericField],
+            'invalid DBRef: Serializable' => [false, new BSONDocument($dbrefInNumericField)],
+            'invalid DBRef: Document' => [false, Document::fromPHP($dbrefInNumericField)],
+            // Additional invalid cases
+            'Update document' => [false, ['$set' => ['foo' => 'bar']]],
+            'Replacement document with DBRef' => [false, ['x' => ['$ref' => 'foo', '$id' => 'bar']]],
         ];
     }
 
diff --git a/tests/Operation/CountDocumentsFunctionalTest.php b/tests/Operation/CountDocumentsFunctionalTest.php
index aaec28480..21415428d 100644
--- a/tests/Operation/CountDocumentsFunctionalTest.php
+++ b/tests/Operation/CountDocumentsFunctionalTest.php
@@ -2,11 +2,46 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\CountDocuments;
 use MongoDB\Operation\InsertMany;
+use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 class CountDocumentsFunctionalTest extends FunctionalTestCase
 {
+    /** @dataProvider provideFilterDocuments */
+    public function testFilterDocuments($filter, stdClass $expectedMatchStage): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new CountDocuments(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $filter
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedMatchStage): void {
+                $this->assertEquals($expectedMatchStage, $event['started']->getCommand()->pipeline[0]->{'$match'} ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expectedQuery = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expectedQuery],
+            'object' => [(object) ['x' => 1], $expectedQuery],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
+            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
+        ];
+    }
+
     public function testEmptyCollection(): void
     {
         $operation = new CountDocuments($this->getDatabaseName(), $this->getCollectionName(), []);
diff --git a/tests/Operation/CountFunctionalTest.php b/tests/Operation/CountFunctionalTest.php
index 550dcbe00..3f44db2b7 100644
--- a/tests/Operation/CountFunctionalTest.php
+++ b/tests/Operation/CountFunctionalTest.php
@@ -2,13 +2,47 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Count;
 use MongoDB\Operation\CreateIndexes;
 use MongoDB\Operation\InsertMany;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 class CountFunctionalTest extends FunctionalTestCase
 {
+    /** @dataProvider provideFilterDocuments */
+    public function testFilterDocuments($filter, stdClass $expectedQuery): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new Count(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $filter
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedQuery): void {
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->query ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expectedQuery = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expectedQuery],
+            'object' => [(object) ['x' => 1], $expectedQuery],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
+            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
+        ];
+    }
+
     public function testDefaultReadConcernIsOmitted(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/CreateIndexesFunctionalTest.php b/tests/Operation/CreateIndexesFunctionalTest.php
index d3d1b8e63..13deb386c 100644
--- a/tests/Operation/CreateIndexesFunctionalTest.php
+++ b/tests/Operation/CreateIndexesFunctionalTest.php
@@ -3,9 +3,11 @@
 namespace MongoDB\Tests\Operation;
 
 use InvalidArgumentException;
+use MongoDB\BSON\Document;
 use MongoDB\Driver\Exception\RuntimeException;
 use MongoDB\Driver\Server;
 use MongoDB\Exception\UnsupportedException;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Model\IndexInfo;
 use MongoDB\Operation\CreateIndexes;
 use MongoDB\Operation\ListIndexes;
@@ -78,15 +80,16 @@ public function testCreateTTLIndex(): void
         });
     }
 
-    public function testCreateIndexes(): void
+    /** @dataProvider provideKeyCasts */
+    public function testCreateIndexes(callable $cast): void
     {
         $expectedNames = ['x_1', 'y_-1_z_1', 'g_2dsphere_z_1', 'my_ttl'];
 
         $indexes = [
-            ['key' => ['x' => 1], 'sparse' => true, 'unique' => true],
-            ['key' => ['y' => -1, 'z' => 1]],
-            ['key' => ['g' => '2dsphere', 'z' => 1]],
-            ['key' => ['t' => 1], 'expireAfterSeconds' => 0, 'name' => 'my_ttl'],
+            ['key' => $cast(['x' => 1]), 'sparse' => true, 'unique' => true],
+            ['key' => $cast(['y' => -1, 'z' => 1])],
+            ['key' => $cast(['g' => '2dsphere', 'z' => 1])],
+            ['key' => $cast(['t' => 1]), 'expireAfterSeconds' => 0, 'name' => 'my_ttl'],
         ];
 
         $operation = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes);
@@ -119,6 +122,20 @@ public function testCreateIndexes(): void
         });
     }
 
+    public function provideKeyCasts(): array
+    {
+        // phpcs:disable SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing
+        // phpcs:disable Squiz.Functions.MultiLineFunctionDeclaration
+        // phpcs:disable Squiz.WhiteSpace.ScopeClosingBrace.ContentBefore
+        return [
+            'array' => [function ($key) { return $key; }],
+            'object' => [function ($key) { return (object) $key; }],
+            'Serializable' => [function ($key) { return new BSONDocument($key); }],
+            'Document' => [function ($key) { return Document::fromPHP($key); }],
+        ];
+        // phpcs:enable
+    }
+
     public function testCreateConflictingIndexesWithCommand(): void
     {
         $indexes = [
diff --git a/tests/Operation/CreateIndexesTest.php b/tests/Operation/CreateIndexesTest.php
index 06a558eca..80db10078 100644
--- a/tests/Operation/CreateIndexesTest.php
+++ b/tests/Operation/CreateIndexesTest.php
@@ -2,7 +2,10 @@
 
 namespace MongoDB\Tests\Operation;
 
+use Generator;
+use MongoDB\BSON\Document;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\CreateIndexes;
 use stdClass;
 
@@ -56,6 +59,7 @@ public function testConstructorRequiresAtLeastOneIndex(): void
     public function testConstructorRequiresIndexSpecificationsToBeAnArray($index): void
     {
         $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected $index[0] to have type "array"');
         new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [$index]);
     }
 
@@ -63,4 +67,52 @@ public function provideInvalidIndexSpecificationTypes()
     {
         return $this->wrapValuesForDataProvider($this->getInvalidArrayValues());
     }
+
+    public function testConstructorRequiresIndexSpecificationKey(): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Required "key" document is missing from index specification');
+        new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [[]]);
+    }
+
+    /** @dataProvider provideInvalidDocumentValues */
+    public function testConstructorRequiresIndexSpecificationKeyToBeADocument($key): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected "key" option to have type "array or object"');
+        new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => $key]]);
+    }
+
+    /** @dataProvider provideKeyDocumentsWithInvalidOrder */
+    public function testConstructorValidatesIndexSpecificationKeyOrder($key): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected order value for "x" field within "key" option to have type "numeric or string"');
+        new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => $key]]);
+    }
+
+    public function provideKeyDocumentsWithInvalidOrder(): Generator
+    {
+        $invalidOrderValues = [true, [], new stdClass(), null];
+
+        foreach ($invalidOrderValues as $order) {
+            yield [['x' => $order]];
+            yield [(object) ['x' => $order]];
+            yield [new BSONDocument(['x' => $order])];
+            yield [Document::fromPHP(['x' => $order])];
+        }
+    }
+
+    /** @dataProvider provideInvalidStringValues */
+    public function testConstructorRequiresIndexSpecificationNameToBeString($name): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected "name" option to have type "string"');
+        new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [['key' => ['x' => 1], 'name' => $name]]);
+    }
+
+    public function provideInvalidStringValues()
+    {
+        return $this->wrapValuesForDataProvider($this->getInvalidStringValues());
+    }
 }
diff --git a/tests/Operation/DatabaseCommandFunctionalTest.php b/tests/Operation/DatabaseCommandFunctionalTest.php
index eee2f2bd2..f113269d0 100644
--- a/tests/Operation/DatabaseCommandFunctionalTest.php
+++ b/tests/Operation/DatabaseCommandFunctionalTest.php
@@ -2,11 +2,46 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\Driver\Command;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\DatabaseCommand;
 use MongoDB\Tests\CommandObserver;
 
 class DatabaseCommandFunctionalTest extends FunctionalTestCase
 {
+    /** @dataProvider provideCommandDocuments */
+    public function testCommandDocuments($command): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($command): void {
+                $operation = new DatabaseCommand(
+                    $this->getDatabaseName(),
+                    $command
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event): void {
+                $this->assertEquals(1, $event['started']->getCommand()->ping ?? null);
+            }
+        );
+    }
+
+    public function provideCommandDocuments(): array
+    {
+        return [
+            'array' => [['ping' => 1]],
+            'object' => [(object) ['ping' => 1]],
+            'Serializable' => [new BSONDocument(['ping' => 1])],
+            'Document' => [Document::fromPHP(['ping' => 1])],
+            'Command:array' => [new Command(['ping' => 1])],
+            'Command:object' => [new Command((object) ['ping' => 1])],
+            'Command:Serializable' => [new Command(new BSONDocument(['ping' => 1]))],
+            'Command:Document' => [new Command(Document::fromPHP(['ping' => 1]))],
+        ];
+    }
+
     public function testSessionOption(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php
index 38166e2aa..01690b090 100644
--- a/tests/Operation/DeleteFunctionalTest.php
+++ b/tests/Operation/DeleteFunctionalTest.php
@@ -2,14 +2,17 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\Collection;
 use MongoDB\DeleteResult;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\BadMethodCallException;
 use MongoDB\Exception\UnsupportedException;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Delete;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 use function version_compare;
 
@@ -25,6 +28,38 @@ public function setUp(): void
         $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
     }
 
+    /** @dataProvider provideFilterDocuments */
+    public function testFilterDocuments($filter, stdClass $expectedQuery): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new Delete(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $filter,
+                    1
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedQuery): void {
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->deletes[0]->q ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expectedQuery = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expectedQuery],
+            'object' => [(object) ['x' => 1], $expectedQuery],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
+            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
+        ];
+    }
+
     public function testDeleteOne(): void
     {
         $this->createFixtures(3);
diff --git a/tests/Operation/DistinctFunctionalTest.php b/tests/Operation/DistinctFunctionalTest.php
index c05b80f70..8e97f48d9 100644
--- a/tests/Operation/DistinctFunctionalTest.php
+++ b/tests/Operation/DistinctFunctionalTest.php
@@ -2,9 +2,12 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\Driver\BulkWrite;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Distinct;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 use function is_scalar;
 use function json_encode;
@@ -12,6 +15,38 @@
 
 class DistinctFunctionalTest extends FunctionalTestCase
 {
+    /** @dataProvider provideFilterDocuments */
+    public function testFilterDocuments($filter, stdClass $expectedQuery): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new Distinct(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    'x',
+                    $filter
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedQuery): void {
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->query ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expectedQuery = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expectedQuery],
+            'object' => [(object) ['x' => 1], $expectedQuery],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
+            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
+        ];
+    }
+
     public function testDefaultReadConcernIsOmitted(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php
index d90c4d930..4680ec84c 100644
--- a/tests/Operation/FindAndModifyFunctionalTest.php
+++ b/tests/Operation/FindAndModifyFunctionalTest.php
@@ -2,19 +2,115 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\Exception\CommandException;
 use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\UnsupportedException;
+use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\FindAndModify;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 use function version_compare;
 
 class FindAndModifyFunctionalTest extends FunctionalTestCase
 {
+    /** @dataProvider provideQueryDocuments */
+    public function testQueryDocuments($query, stdClass $expectedQuery): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($query): void {
+                $operation = new FindAndModify(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    ['query' => $query, 'remove' => true]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedQuery): void {
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->query ?? null);
+            }
+        );
+    }
+
+    public function provideQueryDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expected],
+            'object' => [(object) ['x' => 1], $expected],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'Document' => [Document::fromPHP(['x' => 1]), $expected],
+        ];
+    }
+
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
+     */
+    public function testUpdateDocuments($update, $expectedUpdate): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($update): void {
+                $operation = new FindAndModify(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [
+                        'query' => ['x' => 1],
+                        'update' => $update,
+                    ]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedUpdate): void {
+                $this->assertEquals($expectedUpdate, $event['started']->getCommand()->update ?? null);
+            }
+        );
+    }
+
+    public function provideReplacementDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+
+        return [
+            'replacement:array' => [['x' => 1], $expected],
+            'replacement:object' => [(object) ['x' => 1], $expected],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
+        ];
+    }
+
+    public function provideUpdateDocuments(): array
+    {
+        $expected = (object) ['$set' => (object) ['x' => 1]];
+
+        return [
+            'update:array' => [['$set' => ['x' => 1]], $expected],
+            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
+        ];
+    }
+
+    public function provideUpdatePipelines(): array
+    {
+        $expected = [(object) ['$set' => (object) ['x' => 1]]];
+
+        return [
+            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
+            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
+            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
+        ];
+    }
+
     /** @see https://jira.mongodb.org/browse/PHPLIB-344 */
     public function testManagerReadConcernIsOmitted(): void
     {
diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php
index 6ea8b5840..42f11ba7e 100644
--- a/tests/Operation/FindFunctionalTest.php
+++ b/tests/Operation/FindFunctionalTest.php
@@ -2,17 +2,83 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\ReadPreference;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\CreateCollection;
 use MongoDB\Operation\CreateIndexes;
 use MongoDB\Operation\Find;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 use function microtime;
 
 class FindFunctionalTest extends FunctionalTestCase
 {
+    /** @dataProvider provideFilterDocuments */
+    public function testFilterDocuments($filter, stdClass $expectedQuery): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new Find(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $filter
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedQuery): void {
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->filter ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expectedQuery = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expectedQuery],
+            'object' => [(object) ['x' => 1], $expectedQuery],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
+            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
+        ];
+    }
+
+    /** @dataProvider provideModifierDocuments */
+    public function testModifierDocuments($modifiers, stdClass $expectedSort): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($modifiers): void {
+                $operation = new Find(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [],
+                    ['modifiers' => $modifiers]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedSort): void {
+                $this->assertEquals($expectedSort, $event['started']->getCommand()->sort ?? null);
+            }
+        );
+    }
+
+    public function provideModifierDocuments(): array
+    {
+        $expectedSort = (object) ['x' => 1];
+
+        return [
+            'array' => [['$orderby' => ['x' => 1]], $expectedSort],
+            'object' => [(object) ['$orderby' => ['x' => 1]], $expectedSort],
+            'Serializable' => [new BSONDocument(['$orderby' => ['x' => 1]]), $expectedSort],
+            'Document' => [Document::fromPHP(['$orderby' => ['x' => 1]]), $expectedSort],
+        ];
+    }
+
     public function testDefaultReadConcernIsOmitted(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/FindOneAndReplaceTest.php b/tests/Operation/FindOneAndReplaceTest.php
index 50ae76e75..c50777055 100644
--- a/tests/Operation/FindOneAndReplaceTest.php
+++ b/tests/Operation/FindOneAndReplaceTest.php
@@ -2,7 +2,11 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+//use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+//use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\FindOneAndReplace;
 
 class FindOneAndReplaceTest extends TestCase
@@ -21,11 +25,29 @@ public function testConstructorReplacementArgumentTypeCheck($replacement): void
         new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement);
     }
 
-    public function testConstructorReplacementArgumentRequiresNoOperators(): void
+    /** @dataProvider provideInvalidReplacementValues */
+    public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->expectExceptionMessage('First key in $replacement argument is an update operator');
-        new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], ['$set' => ['x' => 1]]);
+        new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement);
+    }
+
+    public function provideInvalidReplacementValues(): array
+    {
+        return [
+            'update:array' => [['$set' => ['x' => 1]]],
+            'update:object' => [(object) ['$set' => ['x' => 1]]],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
+            // TODO: Enable the following tests when implementing PHPLIB-1129
+            //'pipeline:array' => [[['$set' => ['x' => 1]]]],
+            //'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
+            //'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
+            //'empty_pipeline:array' => [[]],
+            //'empty_pipeline:Serializable' => [new BSONArray([])],
+            //'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
     }
 
     /** @dataProvider provideInvalidConstructorOptions */
diff --git a/tests/Operation/FindOneAndUpdateTest.php b/tests/Operation/FindOneAndUpdateTest.php
index 1ba51f166..2b57b7f5b 100644
--- a/tests/Operation/FindOneAndUpdateTest.php
+++ b/tests/Operation/FindOneAndUpdateTest.php
@@ -2,7 +2,11 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\FindOneAndUpdate;
 
 class FindOneAndUpdateTest extends TestCase
@@ -21,11 +25,25 @@ public function testConstructorUpdateArgumentTypeCheck($update): void
         new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], $update);
     }
 
-    public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline(): void
+    /** @dataProvider provideInvalidUpdateValues */
+    public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
-        new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], []);
+        new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], $update);
+    }
+
+    public function provideInvalidUpdateValues(): array
+    {
+        return [
+            'replacement:array' => [['x' => 1]],
+            'replacement:object' => [(object) ['x' => 1]],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
+            'replacement:Document' => [Document::fromPHP(['x' => 1])],
+            'empty_pipeline:array' => [[]],
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
     }
 
     /** @dataProvider provideInvalidConstructorOptions */
diff --git a/tests/Operation/InsertManyFunctionalTest.php b/tests/Operation/InsertManyFunctionalTest.php
index 533cd8fce..4d47ea104 100644
--- a/tests/Operation/InsertManyFunctionalTest.php
+++ b/tests/Operation/InsertManyFunctionalTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\BSON\ObjectId;
 use MongoDB\Collection;
 use MongoDB\Driver\WriteConcern;
@@ -23,32 +24,94 @@ public function setUp(): void
         $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
     }
 
+    public function testDocumentEncoding(): void
+    {
+        $documents = [
+            ['_id' => 1],
+            (object) ['_id' => 2],
+            new BSONDocument(['_id' => 3]),
+            Document::fromPHP(['_id' => 4]),
+            ['x' => 1],
+            (object) ['x' => 2],
+            new BSONDocument(['x' => 3]),
+            Document::fromPHP(['x' => 4]),
+        ];
+
+        $expectedDocuments = [
+            (object) ['_id' => 1],
+            (object) ['_id' => 2],
+            (object) ['_id' => 3],
+            (object) ['_id' => 4],
+            // Note: _id placeholders must be replaced with generated ObjectIds
+            (object) ['_id' => null, 'x' => 1],
+            (object) ['_id' => null, 'x' => 2],
+            (object) ['_id' => null, 'x' => 3],
+            (object) ['_id' => null, 'x' => 4],
+        ];
+
+        (new CommandObserver())->observe(
+            function () use ($documents, $expectedDocuments): void {
+                $operation = new InsertMany(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $documents
+                );
+
+                $result = $operation->execute($this->getPrimaryServer());
+                $insertedIds = $result->getInsertedIds();
+
+                foreach ($expectedDocuments as $i => $expectedDocument) {
+                    // Replace _id placeholder if necessary
+                    if ($expectedDocument->_id === null) {
+                        $expectedDocument->_id = $insertedIds[$i];
+                    }
+                }
+            },
+            function (array $event) use ($expectedDocuments): void {
+                $this->assertEquals($expectedDocuments, $event['started']->getCommand()->documents ?? null);
+            }
+        );
+    }
+
     public function testInsertMany(): void
     {
         $documents = [
-            ['_id' => 'foo', 'x' => 11],
-            ['x' => 22],
-            (object) ['_id' => 'bar', 'x' => 33],
-            new BSONDocument(['_id' => 'baz', 'x' => 44]),
+            ['_id' => 1],
+            (object) ['_id' => 2],
+            new BSONDocument(['_id' => 3]),
+            Document::fromPHP(['_id' => 4]),
+            ['x' => 1],
+            (object) ['x' => 2],
+            new BSONDocument(['x' => 3]),
+            Document::fromPHP(['x' => 4]),
         ];
 
         $operation = new InsertMany($this->getDatabaseName(), $this->getCollectionName(), $documents);
         $result = $operation->execute($this->getPrimaryServer());
 
         $this->assertInstanceOf(InsertManyResult::class, $result);
-        $this->assertSame(4, $result->getInsertedCount());
+        $this->assertSame(8, $result->getInsertedCount());
 
         $insertedIds = $result->getInsertedIds();
-        $this->assertSame('foo', $insertedIds[0]);
-        $this->assertInstanceOf(ObjectId::class, $insertedIds[1]);
-        $this->assertSame('bar', $insertedIds[2]);
-        $this->assertSame('baz', $insertedIds[3]);
+        $this->assertSame(1, $insertedIds[0]);
+        $this->assertSame(2, $insertedIds[1]);
+        $this->assertSame(3, $insertedIds[2]);
+        $this->assertSame(4, $insertedIds[3]);
+        $this->assertInstanceOf(ObjectId::class, $insertedIds[4]);
+        $this->assertInstanceOf(ObjectId::class, $insertedIds[5]);
+        $this->assertInstanceOf(ObjectId::class, $insertedIds[6]);
+        $this->assertInstanceOf(ObjectId::class, $insertedIds[7]);
 
         $expected = [
-            ['_id' => 'foo', 'x' => 11],
-            ['_id' => $insertedIds[1], 'x' => 22],
-            ['_id' => 'bar', 'x' => 33],
-            ['_id' => 'baz', 'x' => 44],
+            ['_id' => 1],
+            ['_id' => 2],
+            ['_id' => 3],
+            ['_id' => 4],
+            ['_id' => $insertedIds[4], 'x' => 1],
+            ['_id' => $insertedIds[5], 'x' => 2],
+            ['_id' => $insertedIds[6], 'x' => 3],
+            ['_id' => $insertedIds[7], 'x' => 4],
+
         ];
 
         $this->assertSameDocuments($expected, $this->collection->find());
diff --git a/tests/Operation/InsertOneFunctionalTest.php b/tests/Operation/InsertOneFunctionalTest.php
index 93bc26cb5..ce2dcdf3f 100644
--- a/tests/Operation/InsertOneFunctionalTest.php
+++ b/tests/Operation/InsertOneFunctionalTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\BSON\ObjectId;
 use MongoDB\Collection;
 use MongoDB\Driver\WriteConcern;
@@ -10,6 +11,7 @@
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\InsertOne;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
 class InsertOneFunctionalTest extends FunctionalTestCase
 {
@@ -23,36 +25,76 @@ public function setUp(): void
         $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
     }
 
-    /** @dataProvider provideDocumentWithExistingId */
-    public function testInsertOneWithExistingId($document): void
+    /**
+     * @dataProvider provideDocumentsWithIds
+     * @dataProvider provideDocumentsWithoutIds
+     */
+    public function testDocumentEncoding($document, stdClass $expectedDocument): void
     {
-        $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document);
-        $result = $operation->execute($this->getPrimaryServer());
+        (new CommandObserver())->observe(
+            function () use ($document, $expectedDocument): void {
+                $operation = new InsertOne(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $document
+                );
 
-        $this->assertInstanceOf(InsertOneResult::class, $result);
-        $this->assertSame(1, $result->getInsertedCount());
-        $this->assertSame('foo', $result->getInsertedId());
+                $result = $operation->execute($this->getPrimaryServer());
 
-        $expected = [
-            ['_id' => 'foo', 'x' => 11],
-        ];
+                // Replace _id placeholder if necessary
+                if ($expectedDocument->_id === null) {
+                    $expectedDocument->_id = $result->getInsertedId();
+                }
+            },
+            function (array $event) use ($expectedDocument): void {
+                $this->assertEquals($expectedDocument, $event['started']->getCommand()->documents[0] ?? null);
+            }
+        );
+    }
 
-        $this->assertSameDocuments($expected, $this->collection->find());
+    public function provideDocumentsWithIds(): array
+    {
+        $expectedDocument = (object) ['_id' => 1];
+
+        return [
+            'with_id:array' => [['_id' => 1], $expectedDocument],
+            'with_id:object' => [(object) ['_id' => 1], $expectedDocument],
+            'with_id:Serializable' => [new BSONDocument(['_id' => 1]), $expectedDocument],
+            'with_id:Document' => [Document::fromPHP(['_id' => 1]), $expectedDocument],
+        ];
     }
 
-    public function provideDocumentWithExistingId()
+    public function provideDocumentsWithoutIds(): array
     {
+        /* Note: _id placeholders must be replaced with generated ObjectIds. We
+         * also clone the value for each data set since tests will may modify
+         * the object. */
+        $expectedDocument = (object) ['_id' => null, 'x' => 1];
+
         return [
-            [['_id' => 'foo', 'x' => 11]],
-            [(object) ['_id' => 'foo', 'x' => 11]],
-            [new BSONDocument(['_id' => 'foo', 'x' => 11])],
+            'without_id:array' => [['x' => 1], clone $expectedDocument],
+            'without_id:object' => [(object) ['x' => 1], clone $expectedDocument],
+            'without_id:Serializable' => [new BSONDocument(['x' => 1]), clone $expectedDocument],
+            'without_id:Document' => [Document::fromPHP(['x' => 1]), clone $expectedDocument],
         ];
     }
 
-    public function testInsertOneWithGeneratedId(): void
+    /** @dataProvider provideDocumentsWithIds */
+    public function testInsertOneWithExistingId($document, stdClass $expectedDocument): void
     {
-        $document = ['x' => 11];
+        $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document);
+        $result = $operation->execute($this->getPrimaryServer());
 
+        $this->assertInstanceOf(InsertOneResult::class, $result);
+        $this->assertSame(1, $result->getInsertedCount());
+        $this->assertSame($expectedDocument->_id, $result->getInsertedId());
+
+        $this->assertSameDocuments([$expectedDocument], $this->collection->find());
+    }
+
+    /** @dataProvider provideDocumentsWithoutIds */
+    public function testInsertOneWithGeneratedId($document, stdClass $expectedDocument): void
+    {
         $operation = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), $document);
         $result = $operation->execute($this->getPrimaryServer());
 
@@ -60,11 +102,10 @@ public function testInsertOneWithGeneratedId(): void
         $this->assertSame(1, $result->getInsertedCount());
         $this->assertInstanceOf(ObjectId::class, $result->getInsertedId());
 
-        $expected = [
-            ['_id' => $result->getInsertedId(), 'x' => 11],
-        ];
+        // Replace _id placeholder
+        $expectedDocument->_id = $result->getInsertedId();
 
-        $this->assertSameDocuments($expected, $this->collection->find());
+        $this->assertSameDocuments([$expectedDocument], $this->collection->find());
     }
 
     public function testSessionOption(): void
diff --git a/tests/Operation/ReplaceOneTest.php b/tests/Operation/ReplaceOneTest.php
index bf73029d2..2b4446fc1 100644
--- a/tests/Operation/ReplaceOneTest.php
+++ b/tests/Operation/ReplaceOneTest.php
@@ -2,7 +2,10 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+//use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+//use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\ReplaceOne;
 
@@ -31,14 +34,6 @@ public function testConstructorReplacementArgument($replacement): void
         new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
     }
 
-    /** @dataProvider provideUpdateDocuments */
-    public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void
-    {
-        $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('First key in $replacement argument is an update operator');
-        new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
-    }
-
     public function provideReplacementDocuments()
     {
         return $this->wrapValuesForDataProvider([
@@ -48,12 +43,28 @@ public function provideReplacementDocuments()
         ]);
     }
 
-    public function provideUpdateDocuments()
+    /** @dataProvider provideInvalidReplacementValues */
+    public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('First key in $replacement argument is an update operator');
+        new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
+    }
+
+    public function provideInvalidReplacementValues(): array
     {
-        return $this->wrapValuesForDataProvider([
-            ['$set' => ['y' => 1]],
-            (object) ['$set' => ['y' => 1]],
-            new BSONDocument(['$set' => ['y' => 1]]),
-        ]);
+        return [
+            'update:array' => [['$set' => ['x' => 1]]],
+            'update:object' => [(object) ['$set' => ['x' => 1]]],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
+            // TODO: Enable the following tests when implementing PHPLIB-1129
+            //'pipeline:array' => [[['$set' => ['x' => 1]]]],
+            //'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
+            //'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
+            //'empty_pipeline:array' => [[]],
+            //'empty_pipeline:Serializable' => [new BSONArray([])],
+            //'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
     }
 }
diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php
index 8fcd7c5f0..e6a24217e 100644
--- a/tests/Operation/UpdateFunctionalTest.php
+++ b/tests/Operation/UpdateFunctionalTest.php
@@ -2,16 +2,22 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\BSON\ObjectId;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Collection;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\BadMethodCallException;
 use MongoDB\Exception\UnsupportedException;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Update;
 use MongoDB\Tests\CommandObserver;
 use MongoDB\UpdateResult;
+use stdClass;
 
+use function is_array;
 use function version_compare;
 
 class UpdateFunctionalTest extends FunctionalTestCase
@@ -26,6 +32,101 @@ public function setUp(): void
         $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
     }
 
+    /** @dataProvider provideFilterDocuments */
+    public function testFilterDocuments($filter, stdClass $expectedFilter): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new Update(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    $filter,
+                    ['$set' => ['x' => 1]]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedFilter): void {
+                $this->assertEquals($expectedFilter, $event['started']->getCommand()->updates[0]->q ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expected],
+            'object' => [(object) ['x' => 1], $expected],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'Document' => [Document::fromPHP(['x' => 1]), $expected],
+        ];
+    }
+
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
+     */
+    public function testUpdateDocuments($update, $expectedUpdate): void
+    {
+        if (is_array($expectedUpdate) && version_compare($this->getServerVersion(), '4.2.0', '<')) {
+            $this->markTestSkipped('Pipeline-style updates are not supported');
+        }
+
+        (new CommandObserver())->observe(
+            function () use ($update): void {
+                $operation = new Update(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    ['x' => 1],
+                    $update
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedUpdate): void {
+                $this->assertEquals($expectedUpdate, $event['started']->getCommand()->updates[0]->u ?? null);
+            }
+        );
+    }
+
+    public function provideReplacementDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+
+        return [
+            'replacement:array' => [['x' => 1], $expected],
+            'replacement:object' => [(object) ['x' => 1], $expected],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
+        ];
+    }
+
+    public function provideUpdateDocuments(): array
+    {
+        $expected = (object) ['$set' => (object) ['x' => 1]];
+
+        return [
+            'update:array' => [['$set' => ['x' => 1]], $expected],
+            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
+        ];
+    }
+
+    public function provideUpdatePipelines(): array
+    {
+        $expected = [(object) ['$set' => (object) ['x' => 1]]];
+
+        return [
+            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
+            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
+            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
+        ];
+    }
+
     public function testSessionOption(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/UpdateManyTest.php b/tests/Operation/UpdateManyTest.php
index 4636431da..02b2c1ae1 100644
--- a/tests/Operation/UpdateManyTest.php
+++ b/tests/Operation/UpdateManyTest.php
@@ -2,7 +2,10 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\UpdateMany;
 
@@ -31,23 +34,6 @@ public function testConstructorUpdateArgument($update): void
         new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    /** @dataProvider provideReplacementDocuments */
-    public function testConstructorUpdateArgumentRequiresOperators($replacement): void
-    {
-        $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
-        new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
-    }
-
-    public function provideReplacementDocuments()
-    {
-        return $this->wrapValuesForDataProvider([
-            ['y' => 1],
-            (object) ['y' => 1],
-            new BSONDocument(['y' => 1]),
-        ]);
-    }
-
     public function provideUpdateDocuments()
     {
         return $this->wrapValuesForDataProvider([
@@ -56,4 +42,25 @@ public function provideUpdateDocuments()
             new BSONDocument(['$set' => ['y' => 1]]),
         ]);
     }
+
+    /** @dataProvider provideInvalidUpdateValues */
+    public function testConstructorUpdateArgumentRequiresOperators($update): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
+        new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
+    }
+
+    public function provideInvalidUpdateValues(): array
+    {
+        return [
+            'replacement:array' => [['x' => 1]],
+            'replacement:object' => [(object) ['x' => 1]],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
+            'replacement:Document' => [Document::fromPHP(['x' => 1])],
+            'empty_pipeline:array' => [[]],
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
 }
diff --git a/tests/Operation/UpdateOneTest.php b/tests/Operation/UpdateOneTest.php
index b7164ebc5..fa44e7d06 100644
--- a/tests/Operation/UpdateOneTest.php
+++ b/tests/Operation/UpdateOneTest.php
@@ -2,7 +2,10 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\UpdateOne;
 
@@ -31,23 +34,6 @@ public function testConstructorUpdateArgument($update): void
         new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    /** @dataProvider provideReplacementDocuments */
-    public function testConstructorUpdateArgumentRequiresOperators($replacement): void
-    {
-        $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
-        new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
-    }
-
-    public function provideReplacementDocuments()
-    {
-        return $this->wrapValuesForDataProvider([
-            ['y' => 1],
-            (object) ['y' => 1],
-            new BSONDocument(['y' => 1]),
-        ]);
-    }
-
     public function provideUpdateDocuments()
     {
         return $this->wrapValuesForDataProvider([
@@ -56,4 +42,25 @@ public function provideUpdateDocuments()
             new BSONDocument(['$set' => ['y' => 1]]),
         ]);
     }
+
+    /** @dataProvider provideInvalidUpdateValues */
+    public function testConstructorUpdateArgumentRequiresOperators($update): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
+        new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
+    }
+
+    public function provideInvalidUpdateValues(): array
+    {
+        return [
+            'replacement:array' => [['x' => 1]],
+            'replacement:object' => [(object) ['x' => 1]],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
+            'replacement:Document' => [Document::fromPHP(['x' => 1])],
+            'empty_pipeline:array' => [[]],
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
 }
diff --git a/tests/Operation/UpdateTest.php b/tests/Operation/UpdateTest.php
index e7fe97898..40dce6238 100644
--- a/tests/Operation/UpdateTest.php
+++ b/tests/Operation/UpdateTest.php
@@ -2,7 +2,11 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Update;
 
 class UpdateTest extends TestCase
@@ -64,4 +68,25 @@ public function provideInvalidConstructorOptions()
 
         return $options;
     }
+
+    /** @dataProvider provideInvalidUpdateValues */
+    public function testConstructorMultiOptionRequiresOperators($update): void
+    {
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('"multi" option cannot be true if $update is a replacement document');
+        new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update, ['multi' => true]);
+    }
+
+    public function provideInvalidUpdateValues(): array
+    {
+        return [
+            'replacement:array' => [['x' => 1]],
+            'replacement:object' => [(object) ['x' => 1]],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
+            'replacement:Document' => [Document::fromPHP(['x' => 1])],
+            'empty_pipeline:array' => [[]],
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
 }
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 7ed378e11..8e87a5edb 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -193,6 +193,7 @@ protected function getInvalidBooleanValues(bool $includeNull = false): array
      */
     protected function getInvalidDocumentValues(bool $includeNull = false): array
     {
+        // Note: PackedArray is intentionally omitted here (see: PHPLIB-1137)
         return array_merge([123, 3.14, 'foo', true], $includeNull ? [null] : []);
     }
 

From 118f08409fec7ce8be8664dc7bea0803842f8d2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Mon, 29 May 2023 18:58:56 +0200
Subject: [PATCH 289/321] PHPLIB-802: Send readConcern but not writeConcern to
 explain commands (#1080)

ReadConcern is relevant for query plan evaluation, not WriteConcern. The option is sent only for operations that support ReadConcern.
https://jira.mongodb.org/browse/SERVER-28678?focusedCommentId=3457279&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-3457279
---
 psalm-baseline.xml          | 12 ++++++++----
 src/Operation/Aggregate.php |  9 ++++++++-
 src/Operation/Count.php     |  9 ++++++++-
 src/Operation/Delete.php    |  8 +-------
 src/Operation/Distinct.php  |  9 ++++++++-
 src/Operation/Find.php      |  9 ++++++++-
 src/Operation/Update.php    |  4 ----
 7 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 583e0c94d..1d76ad95b 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -286,10 +286,11 @@
       $this->options['typeMap']
       $this->options['typeMap']
     
-    
+    
       $cmdOptions['maxAwaitTimeMS']
       $cmd[$option]
       $cmd['hint']
+      $cmd['readConcern']
       $options[$option]
       $options['writeConcern']
     
@@ -383,9 +384,10 @@
     
       ! is_array($filter) && ! is_object($filter)
     
-    
+    
       $cmd[$option]
       $cmd['hint']
+      $cmd['readConcern']
       $options['readConcern']
       $options['readPreference']
       $options['session']
@@ -468,8 +470,9 @@
     
       $this->options['typeMap']
     
-    
+    
       $cmd[$option]
+      $cmd['readConcern']
       $options['readConcern']
       $options['readPreference']
       $options['session']
@@ -534,7 +537,8 @@
     
       $options['modifiers'][$modifier[1]]
     
-    
+    
+      $cmd['readConcern']
       $options[$modifier[0]]
       $options[$option]
       $options['readPreference']
diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php
index 040e3c9c9..5b278cdd2 100644
--- a/src/Operation/Aggregate.php
+++ b/src/Operation/Aggregate.php
@@ -309,7 +309,14 @@ public function execute(Server $server)
      */
     public function getCommandDocument(Server $server)
     {
-        return $this->createCommandDocument();
+        $cmd = $this->createCommandDocument();
+
+        // Read concern can change the query plan
+        if (isset($this->options['readConcern'])) {
+            $cmd['readConcern'] = $this->options['readConcern'];
+        }
+
+        return $cmd;
     }
 
     /**
diff --git a/src/Operation/Count.php b/src/Operation/Count.php
index 7e427313c..251ba900a 100644
--- a/src/Operation/Count.php
+++ b/src/Operation/Count.php
@@ -173,7 +173,14 @@ public function execute(Server $server)
      */
     public function getCommandDocument(Server $server)
     {
-        return $this->createCommandDocument();
+        $cmd = $this->createCommandDocument();
+
+        // Read concern can change the query plan
+        if (isset($this->options['readConcern'])) {
+            $cmd['readConcern'] = $this->options['readConcern'];
+        }
+
+        return $cmd;
     }
 
     /**
diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php
index 7ca197f7a..129990ac4 100644
--- a/src/Operation/Delete.php
+++ b/src/Operation/Delete.php
@@ -178,13 +178,7 @@ public function execute(Server $server)
      */
     public function getCommandDocument(Server $server)
     {
-        $cmd = ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]];
-
-        if (isset($this->options['writeConcern'])) {
-            $cmd['writeConcern'] = $this->options['writeConcern'];
-        }
-
-        return $cmd;
+        return ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]];
     }
 
     /**
diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php
index 3c2f93dbd..a249adf71 100644
--- a/src/Operation/Distinct.php
+++ b/src/Operation/Distinct.php
@@ -166,7 +166,14 @@ public function execute(Server $server)
      */
     public function getCommandDocument(Server $server)
     {
-        return $this->createCommandDocument();
+        $cmd = $this->createCommandDocument();
+
+        // Read concern can change the query plan
+        if (isset($this->options['readConcern'])) {
+            $cmd['readConcern'] = $this->options['readConcern'];
+        }
+
+        return $cmd;
     }
 
     /**
diff --git a/src/Operation/Find.php b/src/Operation/Find.php
index 8f1e56f49..ca91cb94c 100644
--- a/src/Operation/Find.php
+++ b/src/Operation/Find.php
@@ -331,7 +331,14 @@ public function execute(Server $server)
      */
     public function getCommandDocument(Server $server)
     {
-        return $this->createCommandDocument();
+        $cmd = $this->createCommandDocument();
+
+        // Read concern can change the query plan
+        if (isset($this->options['readConcern'])) {
+            $cmd['readConcern'] = $this->options['readConcern'];
+        }
+
+        return $cmd;
     }
 
     /**
diff --git a/src/Operation/Update.php b/src/Operation/Update.php
index 96a51c53f..611d581d2 100644
--- a/src/Operation/Update.php
+++ b/src/Operation/Update.php
@@ -228,10 +228,6 @@ public function getCommandDocument(Server $server)
             $cmd['bypassDocumentValidation'] = $this->options['bypassDocumentValidation'];
         }
 
-        if (isset($this->options['writeConcern'])) {
-            $cmd['writeConcern'] = $this->options['writeConcern'];
-        }
-
         return $cmd;
     }
 

From 3052d1a0a0f6386b29c51e61109c926d21123f75 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 30 May 2023 22:29:23 +0800
Subject: [PATCH 290/321] PHPLIB-1115: Fix waitForSnapshot() for MongoDB 7.0+
 (#1083)

This fixes a bug in the original implementation where the method would return even if the query did not match a document. Instead, we should retry if either the query fails to match or a SnapshotUnavailable error is raised.

This issue was only discovered due to increased snapshot latency in MongoDB 7.0-dev. In previous versions, the snapshot was always available by the subsequent queries in testSnapshotQueries(), which uses waitForSnapshot().

Additionally, usleep() is added to avoid spamming the server with retry attempts. The TODO item for hrtime() was also removed, as there's no significant benefit to using it in this context and it's return types are not as convenient as microtime().
---
 tests/DocumentationExamplesTest.php | 23 +++++++++--------------
 1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index c56e62df1..0d512b3b5 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -19,6 +19,7 @@
 use function microtime;
 use function ob_end_clean;
 use function ob_start;
+use function usleep;
 use function var_dump;
 use function version_compare;
 
@@ -1973,27 +1974,21 @@ private function waitForSnapshot(string $databaseName, string $collectionName):
         $collection = new Collection($this->manager, $databaseName, $collectionName);
         $session = $this->manager->startSession(['snapshot' => true]);
 
-        /* Retry until a snapshot query succeeds or ten seconds elapse,
-         * whichwever comes first.
-         *
-         * TODO: use hrtime() once the library requires PHP 7.3+ */
+        // Retry until a snapshot query succeeds or ten seconds elapse.
         $retryUntil = microtime(true) + 10;
 
         do {
             try {
-                $collection->aggregate(
-                    [['$match' => ['_id' => ['$exists' => true]]]],
-                    ['session' => $session]
-                );
-
-                break;
+                if ($collection->findOne([], ['session' => $session]) !== null) {
+                    break;
+                }
             } catch (CommandException $e) {
-                if ($e->getCode() === 246 /* SnapshotUnavailable */) {
-                    continue;
+                if ($e->getCode() !== 246 /* SnapshotUnavailable */) {
+                    throw $e;
                 }
-
-                throw $e;
             }
+
+            usleep(1000);
         } while (microtime(true) < $retryUntil);
     }
 

From 7f0b902d56af69874b9d0a903a91273067d079c4 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 30 May 2023 22:41:48 +0800
Subject: [PATCH 291/321] Remove phpcs:ignore comments for unused use
 statements (#1086)

The line in DropEncryptedCollection was never necessary. The line in CreateEncryptedCollection may have been used at one point since Binary is only referenced in a psalm-var annotation, but phpcs no longer complains.
---
 src/Operation/CreateEncryptedCollection.php | 1 -
 src/Operation/DropEncryptedCollection.php   | 2 --
 2 files changed, 3 deletions(-)

diff --git a/src/Operation/CreateEncryptedCollection.php b/src/Operation/CreateEncryptedCollection.php
index 728c2a161..f36089230 100644
--- a/src/Operation/CreateEncryptedCollection.php
+++ b/src/Operation/CreateEncryptedCollection.php
@@ -17,7 +17,6 @@
 
 namespace MongoDB\Operation;
 
-// phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse
 use MongoDB\BSON\Binary;
 use MongoDB\Driver\ClientEncryption;
 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
diff --git a/src/Operation/DropEncryptedCollection.php b/src/Operation/DropEncryptedCollection.php
index f6a04dbf8..4f43d3a7f 100644
--- a/src/Operation/DropEncryptedCollection.php
+++ b/src/Operation/DropEncryptedCollection.php
@@ -17,8 +17,6 @@
 
 namespace MongoDB\Operation;
 
-// phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses.UnusedUse
-use MongoDB\BSON\Binary;
 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
 use MongoDB\Driver\Server;
 use MongoDB\Exception\InvalidArgumentException;

From d95e7623390b8f657755f6601859d4649612a40d Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Wed, 31 May 2023 13:17:50 +0800
Subject: [PATCH 292/321] PHPLIB-1071: Do not create ECC collection and check
 wire version for QEv2  (#1084)

* Sync spec tests for QEv2 without ECC collection

Synced to mongodb/specifications@eb3d882bb8c08d0f25f54709abcd876caeccba7f

* Check for omitted fields at any level of observed commands

The original logic in the Transactions legacy test runner only handled assertions for top-level fields. This adds logic to check fields within embedded documents, as needed by the CSFLE tests.

* Remove ecc collection from CreateEncryptedCollection and DropEncryptedCollection

* Check wire version for Queryable Encryption support in CreateEncryptedCollection
---
 src/Database.php                              |   1 +
 src/Operation/CreateEncryptedCollection.php   |  13 +-
 src/Operation/DropEncryptedCollection.php     |   3 +-
 .../ClientSideEncryptionSpecTest.php          |   4 +
 tests/SpecTests/FunctionalTestCase.php        |  23 +
 tests/SpecTests/TransactionsSpecTest.php      |   8 +-
 .../etc/data/encryptedFields-Range-Date.json  |  33 +
 .../data/encryptedFields-Range-Decimal.json   |  23 +
 ...ncryptedFields-Range-DecimalPrecision.json |  32 +
 .../data/encryptedFields-Range-Double.json    |  23 +
 ...encryptedFields-Range-DoublePrecision.json |  32 +
 .../etc/data/encryptedFields-Range-Int.json   |  29 +
 .../etc/data/encryptedFields-Range-Long.json  |  29 +
 .../etc/data/encryptedFields.json             |   5 +-
 .../etc/data/range-encryptedFields-Date.json  |  30 +
 ...ge-encryptedFields-DecimalNoPrecision.json |  21 +
 ...ange-encryptedFields-DecimalPrecision.json |  29 +
 ...nge-encryptedFields-DoubleNoPrecision.json |  21 +
 ...range-encryptedFields-DoublePrecision.json |  30 +
 .../etc/data/range-encryptedFields-Int.json   |  27 +
 .../etc/data/range-encryptedFields-Long.json  |  27 +
 .../tests/bypassedCommand.json                |   9 +-
 .../tests/fle2v2-BypassQueryAnalysis.json     |  42 +-
 .../tests/fle2v2-Compact.json                 |   3 -
 .../fle2v2-CreateCollection-OldServer.json    |  62 ++
 .../tests/fle2v2-CreateCollection.json        | 606 ++----------------
 .../tests/fle2v2-Delete.json                  |   6 +-
 ...EncryptedFields-vs-EncryptedFieldsMap.json |   6 -
 .../fle2v2-EncryptedFields-vs-jsonSchema.json |   5 -
 .../fle2v2-EncryptedFieldsMap-defaults.json   |   4 +-
 .../tests/fle2v2-FindOneAndUpdate.json        |   7 -
 .../tests/fle2v2-InsertFind-Indexed.json      |   5 -
 .../tests/fle2v2-InsertFind-Unindexed.json    |   3 -
 .../tests/fle2v2-MissingKey.json              |   3 -
 .../tests/fle2v2-Range-Date-Aggregate.json    |   6 -
 .../tests/fle2v2-Range-Date-Correctness.json  |   3 -
 .../tests/fle2v2-Range-Date-Delete.json       |   7 +-
 .../fle2v2-Range-Date-FindOneAndUpdate.json   |   6 -
 .../tests/fle2v2-Range-Date-InsertFind.json   |   6 -
 .../tests/fle2v2-Range-Date-Update.json       |   6 -
 .../tests/fle2v2-Range-Decimal-Aggregate.json |   6 -
 .../fle2v2-Range-Decimal-Correctness.json     |   3 -
 .../tests/fle2v2-Range-Decimal-Delete.json    |   7 +-
 ...fle2v2-Range-Decimal-FindOneAndUpdate.json |   6 -
 .../fle2v2-Range-Decimal-InsertFind.json      |   6 -
 .../tests/fle2v2-Range-Decimal-Update.json    |   6 -
 ...e2v2-Range-DecimalPrecision-Aggregate.json |   6 -
 ...v2-Range-DecimalPrecision-Correctness.json |   3 -
 .../fle2v2-Range-DecimalPrecision-Delete.json |   7 +-
 ...nge-DecimalPrecision-FindOneAndUpdate.json |   6 -
 ...2v2-Range-DecimalPrecision-InsertFind.json |   6 -
 .../fle2v2-Range-DecimalPrecision-Update.json |   6 -
 .../tests/fle2v2-Range-Double-Aggregate.json  |   6 -
 .../fle2v2-Range-Double-Correctness.json      |   3 -
 .../tests/fle2v2-Range-Double-Delete.json     |   7 +-
 .../fle2v2-Range-Double-FindOneAndUpdate.json |   6 -
 .../tests/fle2v2-Range-Double-InsertFind.json |   6 -
 .../tests/fle2v2-Range-Double-Update.json     |   6 -
 ...le2v2-Range-DoublePrecision-Aggregate.json |   6 -
 ...2v2-Range-DoublePrecision-Correctness.json |   3 -
 .../fle2v2-Range-DoublePrecision-Delete.json  |   7 +-
 ...ange-DoublePrecision-FindOneAndUpdate.json |   6 -
 ...e2v2-Range-DoublePrecision-InsertFind.json |   6 -
 .../fle2v2-Range-DoublePrecision-Update.json  |   6 -
 .../tests/fle2v2-Range-Int-Aggregate.json     |   6 -
 .../tests/fle2v2-Range-Int-Correctness.json   |   3 -
 .../tests/fle2v2-Range-Int-Delete.json        |   7 +-
 .../fle2v2-Range-Int-FindOneAndUpdate.json    |   6 -
 .../tests/fle2v2-Range-Int-InsertFind.json    |   6 -
 .../tests/fle2v2-Range-Int-Update.json        |   6 -
 .../tests/fle2v2-Range-Long-Aggregate.json    |   6 -
 .../tests/fle2v2-Range-Long-Correctness.json  |   3 -
 .../tests/fle2v2-Range-Long-Delete.json       |   7 +-
 .../fle2v2-Range-Long-FindOneAndUpdate.json   |   6 -
 .../tests/fle2v2-Range-Long-InsertFind.json   |   6 -
 .../tests/fle2v2-Range-Long-Update.json       |   6 -
 .../tests/fle2v2-Range-WrongType.json         |   3 -
 .../tests/fle2v2-Update.json                  |   9 +-
 ...v2-validatorAndPartialFieldExpression.json |  18 -
 79 files changed, 617 insertions(+), 855 deletions(-)
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json
 create mode 100644 tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json
 create mode 100644 tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json

diff --git a/src/Database.php b/src/Database.php
index a8338b304..5eea326b2 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -313,6 +313,7 @@ public function createCollection(string $collectionName, array $options = [])
      * @return array A tuple containing the command result document from creating the collection and the modified "encryptedFields" option
      * @throws InvalidArgumentException for parameter/option parsing errors
      * @throws CreateEncryptedCollectionException for any errors creating data keys or creating the collection
+     * @throws UnsupportedException if Queryable Encryption is not supported by the selected server
      */
     public function createEncryptedCollection(string $collectionName, ClientEncryption $clientEncryption, string $kmsProvider, ?array $masterKey, array $options): array
     {
diff --git a/src/Operation/CreateEncryptedCollection.php b/src/Operation/CreateEncryptedCollection.php
index f36089230..7ebaee1e4 100644
--- a/src/Operation/CreateEncryptedCollection.php
+++ b/src/Operation/CreateEncryptedCollection.php
@@ -22,10 +22,12 @@
 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
 use MongoDB\Driver\Server;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Exception\UnsupportedException;
 
 use function array_key_exists;
 use function is_array;
 use function is_object;
+use function MongoDB\server_supports_feature;
 
 /**
  * Create an encrypted collection.
@@ -44,6 +46,9 @@
  */
 class CreateEncryptedCollection implements Executable
 {
+    /** @var integer */
+    private static $wireVersionForQueryableEncryptionV2 = 21;
+
     /** @var CreateCollection */
     private $createCollection;
 
@@ -81,13 +86,12 @@ public function __construct(string $databaseName, string $collectionName, array
 
         $this->createCollection = new CreateCollection($databaseName, $collectionName, $options);
 
-        /** @psalm-var array{eccCollection?: ?string, ecocCollection?: ?string, escCollection?: ?string} */
+        /** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */
         $encryptedFields = (array) $options['encryptedFields'];
         $enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]];
 
         $this->createMetadataCollections = [
             new CreateCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc', $enxcolOptions),
-            new CreateCollection($databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc', $enxcolOptions),
             new CreateCollection($databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc', $enxcolOptions),
         ];
 
@@ -150,9 +154,14 @@ public function createDataKeys(ClientEncryption $clientEncryption, string $kmsPr
      * @see Executable::execute()
      * @return array|object Command result document from creating the encrypted collection
      * @throws DriverRuntimeException for other driver errors (e.g. connection errors)
+     * @throws UnsupportedException if the server does not support Queryable Encryption
      */
     public function execute(Server $server)
     {
+        if (! server_supports_feature($server, self::$wireVersionForQueryableEncryptionV2)) {
+            throw new UnsupportedException('Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.');
+        }
+
         foreach ($this->createMetadataCollections as $createMetadataCollection) {
             $createMetadataCollection->execute($server);
         }
diff --git a/src/Operation/DropEncryptedCollection.php b/src/Operation/DropEncryptedCollection.php
index 4f43d3a7f..e5abfaf37 100644
--- a/src/Operation/DropEncryptedCollection.php
+++ b/src/Operation/DropEncryptedCollection.php
@@ -71,12 +71,11 @@ public function __construct(string $databaseName, string $collectionName, array
             throw InvalidArgumentException::invalidType('"encryptedFields" option', $options['encryptedFields'], ['array', 'object']);
         }
 
-        /** @psalm-var array{eccCollection?: ?string, ecocCollection?: ?string, escCollection?: ?string} */
+        /** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */
         $encryptedFields = (array) $options['encryptedFields'];
 
         $this->dropMetadataCollections = [
             new DropCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'),
-            new DropCollection($databaseName, $encryptedFields['eccCollection'] ?? 'enxcol_.' . $collectionName . '.ecc'),
             new DropCollection($databaseName, $encryptedFields['ecocCollection'] ?? 'enxcol_.' . $collectionName . '.ecoc'),
         ];
 
diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index 5dacac5e9..a15161aa2 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -278,11 +278,15 @@ public function setUp(): void
     /**
      * Assert that the expected and actual command documents match.
      *
+     * Note: this method may modify the $expected object.
+     *
      * @param stdClass $expected Expected command document
      * @param stdClass $actual   Actual command document
      */
     public static function assertCommandMatches(stdClass $expected, stdClass $actual): void
     {
+        static::assertCommandOmittedFields($expected, $actual);
+
         static::assertDocumentsMatch($expected, $actual);
     }
 
diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php
index 3b266fb04..c4cb26787 100644
--- a/tests/SpecTests/FunctionalTestCase.php
+++ b/tests/SpecTests/FunctionalTestCase.php
@@ -16,6 +16,7 @@
 use function json_encode;
 use function MongoDB\BSON\fromJSON;
 use function MongoDB\BSON\toPHP;
+use function property_exists;
 use function sprintf;
 use function version_compare;
 
@@ -95,6 +96,28 @@ public static function assertDocumentsMatch($expectedDocument, $actualDocument,
         static::assertThat($actualDocument, $constraint, $message);
     }
 
+    /**
+     * Assert omitted fields in command documents.
+     *
+     * Note: this method may modify the $expected object.
+     *
+     * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#null-values
+     */
+    protected static function assertCommandOmittedFields(stdClass $expected, stdClass $actual): void
+    {
+        foreach ($expected as $key => $value) {
+            if ($value === null) {
+                static::assertObjectNotHasAttribute($key, $actual);
+                unset($expected->{$key});
+                continue;
+            }
+
+            if ($value instanceof stdClass && property_exists($actual, $key) && $actual->{$key} instanceof stdClass) {
+                static::assertCommandOmittedFields($value, $actual->{$key});
+            }
+        }
+    }
+
     /**
      * Assert data within the outcome collection.
      */
diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php
index caca6c013..768dd0b40 100644
--- a/tests/SpecTests/TransactionsSpecTest.php
+++ b/tests/SpecTests/TransactionsSpecTest.php
@@ -62,6 +62,7 @@ public function tearDown(): void
      *
      * Note: this method may modify the $expected object.
      *
+     * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#command-started-events
      * @param stdClass $expected Expected command document
      * @param stdClass $actual   Actual command document
      */
@@ -100,12 +101,7 @@ public static function assertCommandMatches(stdClass $expected, stdClass $actual
          * preferable to skipping the txnNumber assertion. */
         //unset($expected['txnNumber']);
 
-        foreach ($expected as $key => $value) {
-            if ($value === null) {
-                static::assertObjectNotHasAttribute($key, $actual);
-                unset($expected->{$key});
-            }
-        }
+        static::assertCommandOmittedFields($expected, $actual);
 
         static::assertDocumentsMatch($expected, $actual);
     }
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json
new file mode 100644
index 000000000..b0299be2a
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json
@@ -0,0 +1,33 @@
+{
+    "fields": [
+        {
+            "keyId": {
+                "$binary": {
+                    "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                    "subType": "04"
+                }
+            },
+            "path": "encryptedDate",
+            "bsonType": "date",
+            "queries": {
+                "queryType": "rangePreview",
+                "contention": {
+                    "$numberLong": "0"
+                },
+                "sparsity": {
+                    "$numberLong": "1"
+                },
+                "min": {
+                    "$date": {
+                        "$numberLong": "0"
+                    }
+                },
+                "max": {
+                    "$date": {
+                        "$numberLong": "200"
+                    }
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json
new file mode 100644
index 000000000..8bd79a15f
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json
@@ -0,0 +1,23 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDecimal",
+      "bsonType": "decimal",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json
new file mode 100644
index 000000000..d52974ef5
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json
@@ -0,0 +1,32 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDecimalPrecision",
+      "bsonType": "decimal",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberDecimal": "0.0"
+        },
+        "max": {
+          "$numberDecimal": "200.0"
+        },
+        "precision": {
+          "$numberInt": "2"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json
new file mode 100644
index 000000000..5fbfaa8bd
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json
@@ -0,0 +1,23 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDouble",
+      "bsonType": "double",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json
new file mode 100644
index 000000000..18b40d009
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json
@@ -0,0 +1,32 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDoublePrecision",
+      "bsonType": "double",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberDouble": "0.0"
+        },
+        "max": {
+          "$numberDouble": "200.0"
+        },
+        "precision": {
+          "$numberInt": "2"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json
new file mode 100644
index 000000000..819d0b989
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json
@@ -0,0 +1,29 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedInt",
+      "bsonType": "int",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberInt": "0"
+        },
+        "max": {
+          "$numberInt": "200"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json
new file mode 100644
index 000000000..c500b85b5
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json
@@ -0,0 +1,29 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedLong",
+      "bsonType": "long",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberLong": "0"
+        },
+        "max": {
+          "$numberLong": "200"
+        }
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json
index 2364590e4..88abe5a60 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields.json
@@ -1,7 +1,4 @@
 {
-  "escCollection": "enxcol_.default.esc",
-  "eccCollection": "enxcol_.default.ecc",
-  "ecocCollection": "enxcol_.default.ecoc",
   "fields": [
     {
       "keyId": {
@@ -30,4 +27,4 @@
       "bsonType": "string"
     }
   ]
-}
+}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json
new file mode 100644
index 000000000..e19fc1e18
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json
@@ -0,0 +1,30 @@
+{
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDate",
+        "bsonType": "date",
+        "queries": {
+          "queryType": "rangePreview",
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$date": {
+              "$numberLong": "0"
+          }
+          },
+          "max": {
+            "$date": {
+              "$numberLong": "200"
+          }
+          }
+        }
+      }
+    ]
+}
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json
new file mode 100644
index 000000000..c6d129d4c
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json
@@ -0,0 +1,21 @@
+{
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDecimalNoPrecision",
+        "bsonType": "decimal",
+        "queries": {
+          "queryType": "rangePreview",
+          "sparsity": {
+            "$numberInt": "1"
+          }
+        }
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json
new file mode 100644
index 000000000..c23c3fa92
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json
@@ -0,0 +1,29 @@
+{
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDecimalPrecision",
+      "bsonType": "decimal",
+      "queries": {
+        "queryType": "rangePreview",
+        "sparsity": {
+          "$numberInt": "1"
+        },
+        "min": {
+          "$numberDecimal": "0.0"
+        },
+        "max": {
+          "$numberDecimal": "200.0"
+        },
+        "precision": {
+          "$numberInt": "2"
+        }
+      }
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json
new file mode 100644
index 000000000..4af642271
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json
@@ -0,0 +1,21 @@
+{
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoubleNoPrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "sparsity": {
+            "$numberLong": "1"
+          }
+        }
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json
new file mode 100644
index 000000000..c1f388219
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json
@@ -0,0 +1,30 @@
+{
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedDoublePrecision",
+        "bsonType": "double",
+        "queries": {
+          "queryType": "rangePreview",
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberDouble": "0.0"
+          },
+          "max": {
+            "$numberDouble": "200.0"
+          },
+          "precision": {
+            "$numberInt": "2"
+          }
+        }
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json
new file mode 100644
index 000000000..217bf6743
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json
@@ -0,0 +1,27 @@
+{
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedInt",
+        "bsonType": "int",
+        "queries": {
+          "queryType": "rangePreview",
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberInt": "0"
+          },
+          "max": {
+            "$numberInt": "200"
+          }
+        }
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json
new file mode 100644
index 000000000..0fb87edae
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json
@@ -0,0 +1,27 @@
+{
+    "fields": [
+      {
+        "keyId": {
+          "$binary": {
+            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+            "subType": "04"
+          }
+        },
+        "path": "encryptedLong",
+        "bsonType": "long",
+        "queries": {
+          "queryType": "rangePreview",
+          "sparsity": {
+            "$numberLong": "1"
+          },
+          "min": {
+            "$numberLong": "0"
+          },
+          "max": {
+            "$numberLong": "200"
+          }
+        }
+      }
+    ]
+  }
+  
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/tests/bypassedCommand.json b/tests/SpecTests/client-side-encryption/tests/bypassedCommand.json
index bd0b1c565..18054a70c 100644
--- a/tests/SpecTests/client-side-encryption/tests/bypassedCommand.json
+++ b/tests/SpecTests/client-side-encryption/tests/bypassedCommand.json
@@ -78,7 +78,7 @@
       ]
     },
     {
-      "description": "current op is not bypassed",
+      "description": "kill op is not bypassed",
       "clientOptions": {
         "autoEncryptOpts": {
           "kmsProviders": {
@@ -90,14 +90,15 @@
         {
           "name": "runCommand",
           "object": "database",
-          "command_name": "currentOp",
+          "command_name": "killOp",
           "arguments": {
             "command": {
-              "currentOp": 1
+              "killOp": 1,
+              "op": 1234
             }
           },
           "result": {
-            "errorContains": "command not supported for auto encryption: currentOp"
+            "errorContains": "command not supported for auto encryption: killOp"
           }
         }
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
index 8f98cd6f2..dcc3983ae 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -153,7 +150,44 @@
                   }
                 }
               ],
-              "ordered": true
+              "ordered": true,
+              "encryptionInformation": {
+                "type": 1,
+                "schema": {
+                  "default.default": {
+                    "escCollection": "enxcol_.default.esc",
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": [
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedIndexed",
+                        "bsonType": "string",
+                        "queries": {
+                          "queryType": "equality",
+                          "contention": {
+                            "$numberLong": "0"
+                          }
+                        }
+                      },
+                      {
+                        "keyId": {
+                          "$binary": {
+                            "base64": "q83vqxI0mHYSNBI0VniQEg==",
+                            "subType": "04"
+                          }
+                        },
+                        "path": "encryptedUnindexed",
+                        "bsonType": "string"
+                      }
+                    ]
+                  }
+                }
+              }
             },
             "command_name": "insert"
           }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
index e3d936e34..e47c689bf 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json
new file mode 100644
index 000000000..d5b04b3ea
--- /dev/null
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json
@@ -0,0 +1,62 @@
+{
+  "runOn": [
+    {
+      "minServerVersion": "6.0.0",
+      "maxServerVersion": "6.3.99",
+      "topology": [
+        "replicaset",
+        "sharded",
+        "load-balanced"
+      ]
+    }
+  ],
+  "database_name": "default",
+  "collection_name": "default",
+  "tests": [
+    {
+      "description": "driver returns an error if creating a QEv2 collection on unsupported server",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "aws": {}
+          },
+          "encryptedFieldsMap": {
+            "default.encryptedCollection": {
+              "fields": [
+                {
+                  "path": "firstName",
+                  "bsonType": "string",
+                  "keyId": {
+                    "$binary": {
+                      "base64": "AAAAAAAAAAAAAAAAAAAAAA==",
+                      "subType": "04"
+                    }
+                  }
+                }
+              ]
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "dropCollection",
+          "object": "database",
+          "arguments": {
+            "collection": "encryptedCollection"
+          }
+        },
+        {
+          "name": "createCollection",
+          "object": "database",
+          "arguments": {
+            "collection": "encryptedCollection"
+          },
+          "result": {
+            "errorContains": "Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption."
+          }
+        }
+      ]
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
index 5e197848f..819d2eec3 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
@@ -22,9 +22,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -65,7 +62,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -108,15 +105,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -150,21 +138,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -185,9 +158,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "enxcol_.encryptedCollection.esc",
-                "eccCollection": "enxcol_.encryptedCollection.ecc",
-                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
+                "escCollection": null,
+                "ecocCollection": null,
+                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -243,12 +216,6 @@
                       "subType": "04",
                       "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
                     }
-                  },
-                  "queries": {
-                    "queryType": "equality",
-                    "contention": {
-                      "$numberLong": "0"
-                    }
                   }
                 }
               ]
@@ -280,7 +247,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -323,15 +290,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -365,21 +323,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -400,6 +343,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
+                "escCollection": null,
+                "ecocCollection": null,
+                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -409,12 +355,6 @@
                         "subType": "04",
                         "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
                       }
-                    },
-                    "queries": {
-                      "queryType": "equality",
-                      "contention": {
-                        "$numberLong": "0"
-                      }
                     }
                   }
                 ]
@@ -461,12 +401,6 @@
                       "subType": "04",
                       "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
                     }
-                  },
-                  "queries": {
-                    "queryType": "equality",
-                    "contention": {
-                      "$numberLong": "0"
-                    }
                   }
                 }
               ]
@@ -498,7 +432,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -537,14 +471,6 @@
             "collection": "encryptedCollection"
           }
         },
-        {
-          "name": "assertCollectionNotExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "enxcol_.encryptedCollection.ecc"
-          }
-        },
         {
           "name": "assertCollectionNotExists",
           "object": "testRunner",
@@ -581,15 +507,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -623,21 +540,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -667,12 +569,6 @@
                         "subType": "04",
                         "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
                       }
-                    },
-                    "queries": {
-                      "queryType": "equality",
-                      "contention": {
-                        "$numberLong": "0"
-                      }
                     }
                   }
                 ]
@@ -708,156 +604,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecoc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "encryptedCollection"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        }
-      ]
-    },
-    {
-      "description": "encryptedFieldsMap with cyclic entries does not loop",
-      "clientOptions": {
-        "autoEncryptOpts": {
-          "kmsProviders": {
-            "aws": {}
-          },
-          "encryptedFieldsMap": {
-            "default.encryptedCollection": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
-              "fields": [
-                {
-                  "path": "firstName",
-                  "bsonType": "string",
-                  "keyId": {
-                    "$binary": {
-                      "subType": "04",
-                      "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
-                    }
-                  }
-                }
-              ]
-            },
-            "default.encryptedCollection.esc": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
-              "fields": [
-                {
-                  "path": "firstName",
-                  "bsonType": "string",
-                  "keyId": {
-                    "$binary": {
-                      "subType": "04",
-                      "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
-                    }
-                  }
-                }
-              ]
-            }
-          }
-        }
-      },
-      "operations": [
-        {
-          "name": "dropCollection",
-          "object": "database",
-          "arguments": {
-            "collection": "encryptedCollection"
-          }
-        },
-        {
-          "name": "createCollection",
-          "object": "database",
-          "arguments": {
-            "collection": "encryptedCollection"
-          }
-        },
-        {
-          "name": "assertCollectionExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "enxcol_.encryptedCollection.esc"
-          }
-        },
-        {
-          "name": "assertCollectionExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "enxcol_.encryptedCollection.ecc"
-          }
-        },
-        {
-          "name": "assertCollectionExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "enxcol_.encryptedCollection.ecoc"
-          }
-        },
-        {
-          "name": "assertCollectionExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "encryptedCollection"
-          }
-        },
-        {
-          "name": "assertIndexExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "encryptedCollection",
-            "index": "__safeContent___1"
-          }
-        }
-      ],
-      "expectations": [
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.esc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -875,94 +621,6 @@
             "command_name": "drop",
             "database_name": "default"
           }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.esc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecoc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "encryptedCollection",
-              "encryptedFields": {
-                "escCollection": "enxcol_.encryptedCollection.esc",
-                "eccCollection": "enxcol_.encryptedCollection.ecc",
-                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
-                "fields": [
-                  {
-                    "path": "firstName",
-                    "bsonType": "string",
-                    "keyId": {
-                      "$binary": {
-                        "subType": "04",
-                        "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
-                      }
-                    }
-                  }
-                ]
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
-        {
-          "command_started_event": {
-            "command": {
-              "createIndexes": "encryptedCollection",
-              "indexes": [
-                {
-                  "name": "__safeContent___1",
-                  "key": {
-                    "__safeContent__": 1
-                  }
-                }
-              ]
-            },
-            "command_name": "createIndexes",
-            "database_name": "default"
-          }
         }
       ]
     },
@@ -975,9 +633,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1060,9 +715,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1103,7 +755,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -1146,15 +798,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1188,21 +831,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1223,9 +851,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "enxcol_.encryptedCollection.esc",
-                "eccCollection": "enxcol_.encryptedCollection.ecc",
-                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
+                "escCollection": null,
+                "ecocCollection": null,
+                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -1279,9 +907,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1303,9 +928,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1330,7 +952,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -1373,15 +995,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1415,21 +1028,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1450,9 +1048,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "enxcol_.encryptedCollection.esc",
-                "eccCollection": "enxcol_.encryptedCollection.ecc",
-                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
+                "escCollection": null,
+                "ecocCollection": null,
+                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -1511,9 +1109,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1549,15 +1144,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1595,9 +1181,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1619,9 +1202,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1646,7 +1226,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -1684,9 +1264,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1710,14 +1287,6 @@
             "collection": "enxcol_.encryptedCollection.esc"
           }
         },
-        {
-          "name": "assertCollectionNotExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "enxcol_.encryptedCollection.ecc"
-          }
-        },
         {
           "name": "assertCollectionNotExists",
           "object": "testRunner",
@@ -1745,15 +1314,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1787,21 +1347,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1822,9 +1367,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "enxcol_.encryptedCollection.esc",
-                "eccCollection": "enxcol_.encryptedCollection.ecc",
-                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
+                "escCollection": null,
+                "ecocCollection": null,
+                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -1881,15 +1426,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -1927,9 +1463,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1951,9 +1484,6 @@
           "arguments": {
             "collection": "encryptedCollection",
             "encryptedFields": {
-              "escCollection": "enxcol_.encryptedCollection.esc",
-              "eccCollection": "enxcol_.encryptedCollection.ecc",
-              "ecocCollection": "enxcol_.encryptedCollection.ecoc",
               "fields": [
                 {
                   "path": "firstName",
@@ -1978,7 +1508,7 @@
           }
         },
         {
-          "name": "assertCollectionExists",
+          "name": "assertCollectionNotExists",
           "object": "testRunner",
           "arguments": {
             "database": "default",
@@ -2025,14 +1555,6 @@
             "collection": "enxcol_.encryptedCollection.esc"
           }
         },
-        {
-          "name": "assertCollectionNotExists",
-          "object": "testRunner",
-          "arguments": {
-            "database": "default",
-            "collection": "enxcol_.encryptedCollection.ecc"
-          }
-        },
         {
           "name": "assertCollectionNotExists",
           "object": "testRunner",
@@ -2060,15 +1582,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
-            },
-            "command_name": "drop",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -2102,21 +1615,6 @@
             "database_name": "default"
           }
         },
-        {
-          "command_started_event": {
-            "command": {
-              "create": "enxcol_.encryptedCollection.ecc",
-              "clusteredIndex": {
-                "key": {
-                  "_id": 1
-                },
-                "unique": true
-              }
-            },
-            "command_name": "create",
-            "database_name": "default"
-          }
-        },
         {
           "command_started_event": {
             "command": {
@@ -2137,9 +1635,9 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": "enxcol_.encryptedCollection.esc",
-                "eccCollection": "enxcol_.encryptedCollection.ecc",
-                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
+                "escCollection": null,
+                "ecocCollection": null,
+                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -2211,7 +1709,7 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "enxcol_.encryptedCollection.ecc"
+              "drop": "enxcol_.encryptedCollection.ecoc"
             },
             "command_name": "drop",
             "database_name": "default"
@@ -2220,19 +1718,57 @@
         {
           "command_started_event": {
             "command": {
-              "drop": "enxcol_.encryptedCollection.ecoc"
+              "drop": "encryptedCollection"
             },
             "command_name": "drop",
             "database_name": "default"
           }
+        }
+      ]
+    },
+    {
+      "description": "encryptedFields are consulted for metadata collection names",
+      "clientOptions": {
+        "autoEncryptOpts": {
+          "kmsProviders": {
+            "aws": {}
+          },
+          "encryptedFieldsMap": {
+            "default.encryptedCollection": {
+              "escCollection": "invalid_esc_name",
+              "ecocCollection": "invalid_ecoc_name",
+              "fields": [
+                {
+                  "path": "firstName",
+                  "bsonType": "string",
+                  "keyId": {
+                    "$binary": {
+                      "subType": "04",
+                      "base64": "AAAAAAAAAAAAAAAAAAAAAA=="
+                    }
+                  }
+                }
+              ]
+            }
+          }
+        }
+      },
+      "operations": [
+        {
+          "name": "dropCollection",
+          "object": "database",
+          "arguments": {
+            "collection": "encryptedCollection"
+          }
         },
         {
-          "command_started_event": {
-            "command": {
-              "drop": "encryptedCollection"
-            },
-            "command_name": "drop",
-            "database_name": "default"
+          "name": "createCollection",
+          "object": "database",
+          "arguments": {
+            "collection": "encryptedCollection"
+          },
+          "result": {
+            "errorContains": "Encrypted State Collection name should follow"
           }
         }
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
index 2eb33c96e..e4150eab8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -180,7 +177,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -236,12 +232,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
index b4edec7e1..b579979e9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -95,9 +92,6 @@
           },
           "encryptedFieldsMap": {
             "default.default": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": []
             }
           }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
index a9cabfa1e..0a84d7365 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
@@ -18,9 +18,6 @@
     "bsonType": "object"
   },
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -187,7 +184,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -243,7 +239,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
index d565bdcf1..3e0905ead 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
@@ -74,9 +74,9 @@
                 },
                 "schema": {
                   "default.default": {
-                    "fields": [],
                     "escCollection": "enxcol_.default.esc",
-                    "ecocCollection": "enxcol_.default.ecoc"
+                    "ecocCollection": "enxcol_.default.ecoc",
+                    "fields": []
                   }
                 }
               },
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
index 2124ae401..4606fbb93 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -187,7 +184,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -248,7 +244,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -429,7 +424,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -492,7 +486,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
index e18deac43..c7149d1f5 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -183,7 +180,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -239,7 +235,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
index ef7bfbfd7..008b0c959 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
index c7bbe71c4..0b7e86bca 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
@@ -23,9 +23,6 @@
     }
   ],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
index 0d4e163b2..dea821bd1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -217,7 +214,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -275,7 +271,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -339,7 +334,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
index 35d639f67..9e4f52587 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
index 8f7500eb9..7f4094f50 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -206,7 +203,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -264,7 +260,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -323,12 +318,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
index b9739331f..5ec060160 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -221,7 +218,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -279,7 +275,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -345,7 +340,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
index c9dc66d94..efce1511c 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -213,7 +210,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -271,7 +267,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -330,7 +325,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
index 13e263331..7f9fadcda 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -217,7 +214,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -275,7 +271,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -347,7 +342,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
index cff4558a5..529ca57d3 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
@@ -12,9 +12,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -197,7 +194,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -245,7 +241,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -299,7 +294,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
index ff9f5a9b4..5d0436556 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
@@ -12,9 +12,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
index 1a094b853..c4d855de9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
@@ -12,9 +12,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -188,7 +185,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -236,7 +232,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -285,12 +280,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
index 5dc95283a..eef729830 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
@@ -12,9 +12,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -199,7 +196,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -247,7 +243,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -303,7 +298,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
index 6e881332d..00a25a558 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
@@ -12,9 +12,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -193,7 +190,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -241,7 +237,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -290,7 +285,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
index 9d2cc6995..a9d53fc4f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
@@ -12,9 +12,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -197,7 +194,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -245,7 +241,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -307,7 +302,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
index 876357fa7..801beefe1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -208,7 +205,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -265,7 +261,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -328,7 +323,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
index d8c40a7a8..b8a695361 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
index c219d36e5..1abb59bfd 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -199,7 +196,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -256,7 +252,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -314,12 +309,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
index 7a7a9218e..8d763431f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -210,7 +207,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -267,7 +263,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -332,7 +327,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
index 5453e6c8a..5407fba18 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -204,7 +201,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -261,7 +257,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -319,7 +314,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
index fa94097ef..e5d1a4e05 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -208,7 +205,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -265,7 +261,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -336,7 +331,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
index d6118bfa1..90882c353 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -199,7 +196,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -247,7 +243,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -301,7 +296,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
index e455c72dc..f8e4c5d83 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
index 05a78d614..e10e5e0f6 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -190,7 +187,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -238,7 +234,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -287,12 +282,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
index 6712f7920..a29f7948d 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -201,7 +198,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -249,7 +245,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -305,7 +300,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
index a9d9bed7c..bee3f58e2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -195,7 +192,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -243,7 +239,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -292,7 +287,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
index 91387dd90..1fc605337 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -199,7 +196,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -247,7 +243,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -309,7 +304,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
index a6fd2c164..b121c72f1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -208,7 +205,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -265,7 +261,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -328,7 +323,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
index 00f2754d2..6b42ecfe8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
index 88c2820a2..a5c397d0b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -199,7 +196,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -256,7 +252,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -314,12 +309,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
index 0186f6fd5..b6df9463e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -210,7 +207,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -267,7 +263,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -332,7 +327,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
index b7ce04c7c..1cea25545 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -204,7 +201,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -261,7 +257,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -319,7 +314,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
index 7d799c785..7703c9057 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -208,7 +205,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -265,7 +261,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -336,7 +331,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
index d95d95a11..9c2536264 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -205,7 +202,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -259,7 +255,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -319,7 +314,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
index b5f79c8cb..58ccf3efc 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
index e3217a2a7..b20b2750b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -196,7 +193,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -250,7 +246,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -305,12 +300,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
index 1b729d14e..f9c189ace 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -207,7 +204,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -261,7 +257,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -323,7 +318,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
index 81ded9596..874d4760c 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -201,7 +198,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -255,7 +251,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -310,7 +305,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
index 81120af32..c2b62b4d1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -205,7 +202,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -259,7 +255,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -327,7 +322,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
index 3c17a3238..afc0f97be 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -205,7 +202,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -259,7 +255,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -319,7 +314,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
index db1e69a36..cda941de8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
index 6e32f8d5e..ad344e21b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -196,7 +193,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -250,7 +246,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -305,12 +300,12 @@
                   "limit": 1
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
index 2db5f700f..d44720046 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -207,7 +204,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -261,7 +257,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -323,7 +318,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
index 365c7e5d5..4eb837f28 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -201,7 +198,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -255,7 +251,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -310,7 +305,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
index 3ee000b63..3ba7f17c1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -205,7 +202,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -259,7 +255,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -327,7 +322,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
index c28576554..e5e9ddc82 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
index 5756ed828..14104e2cd 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
@@ -14,9 +14,6 @@
   "collection_name": "default",
   "data": [],
   "encrypted_fields": {
-    "escCollection": "enxcol_.default.esc",
-    "eccCollection": "enxcol_.default.ecc",
-    "ecocCollection": "enxcol_.default.ecoc",
     "fields": [
       {
         "keyId": {
@@ -187,7 +184,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -247,12 +243,12 @@
                   }
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -433,7 +429,6 @@
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
@@ -495,12 +490,12 @@
                   }
                 }
               ],
+              "ordered": true,
               "encryptionInformation": {
                 "type": 1,
                 "schema": {
                   "default.default": {
                     "escCollection": "enxcol_.default.esc",
-                    "eccCollection": "enxcol_.default.ecc",
                     "ecocCollection": "enxcol_.default.ecoc",
                     "fields": [
                       {
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
index b18afb115..4adf6fc07 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
@@ -30,9 +30,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": [
                 {
                   "keyId": {
@@ -109,9 +106,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": [
                 {
                   "keyId": {
@@ -183,9 +177,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": [
                 {
                   "keyId": {
@@ -263,9 +254,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": [
                 {
                   "keyId": {
@@ -346,9 +334,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": [
                 {
                   "keyId": {
@@ -443,9 +428,6 @@
           },
           "encryptedFieldsMap": {
             "default.encryptedCollection": {
-              "escCollection": "enxcol_.default.esc",
-              "eccCollection": "enxcol_.default.ecc",
-              "ecocCollection": "enxcol_.default.ecoc",
               "fields": [
                 {
                   "keyId": {

From f75d3a84b12479b4b7a0260cc83dad20c858e993 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Thu, 1 Jun 2023 09:48:15 +0800
Subject: [PATCH 293/321] PHPLIB-878: Spec tests for queryable encryption range
 indexes (#1064)

* Allow extra fields in aggregate results

Most operations that use ASSERT_SAME_DOCUMENT and ASSERT_SAME_DOCUMENTS should technically use ASSERT_MATCHES_DOCUMENT and ASSERT_DOCUMENTS_MATCH, respectively; however, this is the minimum change needed to satisfy new CSFLE spec tests.

Related to dc1bb17f04d0bda1b62e786e034a437f642a47f6

* Remove skips for queryable encryption range index spec tests

Decimal tests are skipped until bundled libmongocrypt can link a Decimal128 library (see: PHPC-2207)

Long tests are skipped pending a workaround for preserving Int64 types in spec tests.

* Range explicit encryption prose tests

* Decode field paths as BSON to preserve BSON int64 types

* PHPLIB-1110: Consolidate data files for CSFLE spec and prose tests

Synced with mongodb/specifications@c4f3fabe9047e5e7a87877d642fa0d885a47351c
---
 .../FunctionalTestCase.php                    |   2 +-
 .../Prose22_RangeExplicitEncryptionTest.php   | 480 ++++++++++++++++++
 .../ClientSideEncryptionSpecTest.php          | 264 +++-------
 tests/SpecTests/Operation.php                 |   2 +-
 .../etc/data/encryptedFields-Range-Date.json  |  33 --
 .../data/encryptedFields-Range-Decimal.json   |  23 -
 ...ncryptedFields-Range-DecimalPrecision.json |  32 --
 .../data/encryptedFields-Range-Double.json    |  23 -
 ...encryptedFields-Range-DoublePrecision.json |  32 --
 .../etc/data/encryptedFields-Range-Int.json   |  29 --
 .../etc/data/encryptedFields-Range-Long.json  |  29 --
 .../etc/data/range-encryptedFields-Date.json  |  49 +-
 ...ge-encryptedFields-DecimalNoPrecision.json |  36 +-
 ...ange-encryptedFields-DecimalPrecision.json |   5 +-
 ...nge-encryptedFields-DoubleNoPrecision.json |  36 +-
 ...range-encryptedFields-DoublePrecision.json |  54 +-
 .../etc/data/range-encryptedFields-Int.json   |  48 +-
 .../etc/data/range-encryptedFields-Long.json  |  48 +-
 .../tests/fle2v2-Range-Decimal-Aggregate.json |  26 +-
 .../fle2v2-Range-Decimal-Correctness.json     | 138 ++---
 .../tests/fle2v2-Range-Decimal-Delete.json    |  22 +-
 ...fle2v2-Range-Decimal-FindOneAndUpdate.json |  30 +-
 .../fle2v2-Range-Decimal-InsertFind.json      |  26 +-
 .../tests/fle2v2-Range-Decimal-Update.json    |  28 +-
 .../tests/fle2v2-Range-Double-Aggregate.json  |  26 +-
 .../fle2v2-Range-Double-Correctness.json      | 138 ++---
 .../tests/fle2v2-Range-Double-Delete.json     |  22 +-
 .../fle2v2-Range-Double-FindOneAndUpdate.json |  30 +-
 .../tests/fle2v2-Range-Double-InsertFind.json |  26 +-
 .../tests/fle2v2-Range-Double-Update.json     |  28 +-
 30 files changed, 965 insertions(+), 800 deletions(-)
 create mode 100644 tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json
 delete mode 100644 tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json

diff --git a/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php b/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
index 68285f724..08368b0ac 100644
--- a/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
+++ b/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
@@ -69,7 +69,7 @@ protected static function insertKeyVaultData(Client $client, ?array $keyVaultDat
         $collection->insertMany($keyVaultData);
     }
 
-    private function createInt64(string $value): Int64
+    protected static function createInt64(string $value): Int64
     {
         $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value);
         $int64 = sprintf('C:%d:"%s":%d:{%s}', strlen(Int64::class), Int64::class, strlen($array), $array);
diff --git a/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php b/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
new file mode 100644
index 000000000..1c0efb058
--- /dev/null
+++ b/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
@@ -0,0 +1,480 @@
+isStandalone() || ($this->isShardedCluster() && ! $this->isShardedClusterUsingReplicasets())) {
+            $this->markTestSkipped('Range explicit encryption tests require replica sets');
+        }
+
+        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
+            $this->markTestSkipped('Range explicit encryption tests require MongoDB 7.0 or later');
+        }
+
+        $client = static::createTestClient();
+
+        $key1Document = $this->decodeJson(file_get_contents(__DIR__ . '/../client-side-encryption/etc/data/keys/key1-document.json'));
+        $this->key1Id = $key1Document->_id;
+
+        // Drop the key vault collection and insert key1Document with a majority write concern
+        self::insertKeyVaultData($client, [$key1Document]);
+
+        $this->clientEncryption = $client->createClientEncryption([
+            'keyVaultNamespace' => 'keyvault.datakeys',
+            'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]],
+        ]);
+
+        $autoEncryptionOpts = [
+            'keyVaultNamespace' => 'keyvault.datakeys',
+            'kmsProviders' => ['local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY), 0)]],
+            'bypassQueryAnalysis' => true,
+        ];
+
+        $this->encryptedClient = self::createTestClient(null, [], [
+            'autoEncryption' => $autoEncryptionOpts,
+            /* libmongocrypt caches results from listCollections. Use a new
+             * client in each test to ensure its encryptedFields is applied. */
+            'disableClientPersistence' => true,
+        ]);
+    }
+
+    public function setUpWithTypeAndRangeOpts(string $type, array $rangeOpts): void
+    {
+        if ($type === 'DecimalNoPrecision' || $type === 'DecimalPrecision') {
+            $this->markTestSkipped('Bundled libmongocrypt does not support Decimal128 (PHPC-2207)');
+        }
+
+        /* Read the encryptedFields file directly into BSON to preserve typing
+         * for 64-bit integers. This means that DropEncryptedCollection and
+         * CreateEncryptedCollection will be unable to inspect the option for
+         * metadata collection names, but that's not necessary for the test. */
+        $encryptedFields = Document::fromJSON(file_get_contents(__DIR__ . '/../client-side-encryption/etc/data/range-encryptedFields-' . $type . '.json'));
+
+        $database = $this->encryptedClient->selectDatabase($this->getDatabaseName());
+        $database->dropCollection('explicit_encryption', ['encryptedFields' => $encryptedFields]);
+        $database->createCollection('explicit_encryption', ['encryptedFields' => $encryptedFields]);
+        $this->collection = $database->selectCollection('explicit_encryption');
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+        $fieldName = 'encrypted' . $type;
+
+        $this->collection->insertMany([
+            ['_id' => 0, $fieldName => $this->clientEncryption->encrypt($cast(0), $encryptOpts)],
+            ['_id' => 1, $fieldName => $this->clientEncryption->encrypt($cast(6), $encryptOpts)],
+            ['_id' => 2, $fieldName => $this->clientEncryption->encrypt($cast(30), $encryptOpts)],
+            ['_id' => 3, $fieldName => $this->clientEncryption->encrypt($cast(200), $encryptOpts)],
+        ]);
+    }
+
+    public function tearDown(): void
+    {
+        /* Since encryptedClient is created with disableClientPersistence=true,
+         * free any objects that may hold a reference to its mongoc_client_t */
+        $this->collection = null;
+        $this->clientEncryption = null;
+        $this->encryptedClient = null;
+    }
+
+    /** @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#test-setup-rangeopts */
+    public static function provideTypeAndRangeOpts(): Generator
+    {
+        // TODO: skip DecimalNoPrecision test on mongos
+        yield 'DecimalNoPrecision' => [
+            'DecimalNoPrecision',
+            ['sparsity' => 1],
+        ];
+
+        yield 'DecimalPrecision' => [
+            'DecimalPrecision',
+            [
+                'min' => new Decimal128('0'),
+                'max' => new Decimal128('200'),
+                'sparsity' => 1,
+                'precision' => 2,
+            ],
+        ];
+
+        yield 'DoubleNoPrecision' => [
+            'DoubleNoPrecision',
+            ['sparsity' => 1],
+        ];
+
+        yield 'DoublePrecision' => [
+            'DoublePrecision',
+            [
+                'min' => 0.0,
+                'max' => 200.0,
+                'sparsity' => 1,
+                'precision' => 2,
+            ],
+        ];
+
+        yield 'Date' => [
+            'Date',
+            [
+                'min' => new UTCDateTime(0),
+                'max' => new UTCDateTime(200),
+                'sparsity' => 1,
+            ],
+        ];
+
+        yield 'Int' => [
+            'Int',
+            [
+                'min' => 0,
+                'max' => 200,
+                'sparsity' => 1,
+            ],
+        ];
+
+        yield 'Long' => [
+            'Long',
+            [
+                'min' => self::createInt64('0'),
+                'max' => self::createInt64('200'),
+                'sparsity' => 1,
+            ],
+        ];
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-1-can-decrypt-a-payload
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase1_CanDecryptAPayload(string $type, array $rangeOpts): void
+    {
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+        $originalValue = $cast(6);
+
+        $insertPayload = $this->clientEncryption->encrypt($originalValue, $encryptOpts);
+        $decryptedValue = $this->clientEncryption->decrypt($insertPayload);
+
+        /* Decryption of a 64-bit integer will likely result in a scalar int, so
+         * cast it back to an Int64 before comparing to the original value. */
+        if ($type === 'Long' && is_int($decryptedValue)) {
+            $decryptedValue = $cast($decryptedValue);
+        }
+
+        /* Use separate assertions for type and equality as assertSame isn't
+         * suitable for comparing BSON objects and using assertEquals alone
+         * would disregard scalar type differences. */
+        $this->assertSame(get_debug_type($originalValue), get_debug_type($decryptedValue));
+        $this->assertEquals($originalValue, $decryptedValue);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-2-can-find-encrypted-range-and-return-the-maximum
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase2_CanFindEncryptedRangeAndReturnTheMaximum(string $type, array $rangeOpts): void
+    {
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'queryType' => ClientEncryption::QUERY_TYPE_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+        $fieldName = 'encrypted' . $type;
+
+        $expr = [
+            '$and' => [
+                [$fieldName => ['$gte' => $cast(6)]],
+                [$fieldName => ['$lte' => $cast(200)]],
+            ],
+        ];
+
+        $encryptedExpr = $this->clientEncryption->encryptExpression($expr, $encryptOpts);
+        $cursor = $this->collection->find($encryptedExpr, ['sort' => ['_id' => 1]]);
+
+        $expectedDocuments = [
+            ['_id' => 1, $fieldName => $cast(6)],
+            ['_id' => 2, $fieldName => $cast(30)],
+            ['_id' => 3, $fieldName => $cast(200)],
+        ];
+
+        $this->assertMultipleDocumentsMatch($expectedDocuments, $cursor);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-3-can-find-encrypted-range-and-return-the-minimum
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase3_CanFindEncryptedRangeAndReturnTheMinimum(string $type, array $rangeOpts): void
+    {
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'queryType' => ClientEncryption::QUERY_TYPE_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+        $fieldName = 'encrypted' . $type;
+
+        $expr = [
+            '$and' => [
+                [$fieldName => ['$gte' => $cast(0)]],
+                [$fieldName => ['$lte' => $cast(6)]],
+            ],
+        ];
+
+        $encryptedExpr = $this->clientEncryption->encryptExpression($expr, $encryptOpts);
+        $cursor = $this->collection->find($encryptedExpr, ['sort' => ['_id' => 1]]);
+
+        $expectedDocuments = [
+            ['_id' => 0, $fieldName => $cast(0)],
+            ['_id' => 1, $fieldName => $cast(6)],
+        ];
+
+        $this->assertMultipleDocumentsMatch($expectedDocuments, $cursor);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-4-can-find-encrypted-range-with-an-open-range-query
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase4_CanFindEncryptedRangeWithAnOpenRangeQuery(string $type, array $rangeOpts): void
+    {
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'queryType' => ClientEncryption::QUERY_TYPE_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+        $fieldName = 'encrypted' . $type;
+
+        $expr = ['$and' => [[$fieldName => ['$gt' => $cast(30)]]]];
+
+        $encryptedExpr = $this->clientEncryption->encryptExpression($expr, $encryptOpts);
+        $cursor = $this->collection->find($encryptedExpr, ['sort' => ['_id' => 1]]);
+        $expectedDocuments = [['_id' => 3, $fieldName => $cast(200)]];
+
+        $this->assertMultipleDocumentsMatch($expectedDocuments, $cursor);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-5-can-run-an-aggregation-expression-inside-expr
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase5_CanRunAnAggregationExpressionInsideExpr(string $type, array $rangeOpts): void
+    {
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'queryType' => ClientEncryption::QUERY_TYPE_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+        $fieldName = 'encrypted' . $type;
+        $fieldPath = '$' . $fieldName;
+
+        $expr = ['$and' => [['$lt' => [$fieldPath, $cast(30)]]]];
+
+        $encryptedExpr = $this->clientEncryption->encryptExpression($expr, $encryptOpts);
+        $cursor = $this->collection->find(['$expr' => $encryptedExpr], ['sort' => ['_id' => 1]]);
+
+        $expectedDocuments = [
+            ['_id' => 0, $fieldName => $cast(0)],
+            ['_id' => 1, $fieldName => $cast(6)],
+        ];
+
+        $this->assertMultipleDocumentsMatch($expectedDocuments, $cursor);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-6-encrypting-a-document-greater-than-the-maximum-errors
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase6_EncryptingADocumentGreaterThanTheMaximumErrors(string $type, array $rangeOpts): void
+    {
+        if ($type === 'DecimalNoPrecision' || $type === 'DoubleNoPrecision') {
+            $this->markTestSkipped('Test is not applicable to "NoPrecision" types');
+        }
+
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $cast = self::getCastCallableForType($type);
+
+        $this->expectException(EncryptionException::class);
+        $this->expectExceptionMessage('Value must be greater than or equal to the minimum value and less than or equal to the maximum value');
+        $this->clientEncryption->encrypt($cast(201), $encryptOpts);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-7-encrypting-a-value-of-a-different-type-errors
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase7_EncryptingAValueOfADifferentTypeErrors(string $type, array $rangeOpts): void
+    {
+        if ($type === 'DecimalNoPrecision' || $type === 'DoubleNoPrecision') {
+            /* Explicit encryption relies on min/max range options to check
+             * types and "NoPrecision" intentionally omits those options. */
+            $this->markTestSkipped('Test is not applicable to DoubleNoPrecision and DecimalNoPrecision');
+        }
+
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts,
+        ];
+
+        $value = $type === 'Int' ? 6.0 : 6;
+
+        $this->expectException(EncryptionException::class);
+        $this->expectExceptionMessage('expected matching \'min\' and value type');
+        $this->clientEncryption->encrypt($value, $encryptOpts);
+    }
+
+    /**
+     * @see https://github.com/mongodb/specifications/blob/master/source/client-side-encryption/tests/README.rst#case-8-setting-precision-errors-if-the-type-is-not-double-or-decimal128
+     * @dataProvider provideTypeAndRangeOpts
+     */
+    public function testCase8_SettingPrecisionErrorsIfTheTypeIsNotDoubleOrDecimal128(string $type, array $rangeOpts): void
+    {
+        if ($type === 'DecimalNoPrecision' || $type === 'DecimalPrecision' || $type === 'DoubleNoPrecision' || $type === 'DoublePrecision') {
+            $this->markTestSkipped('Test is not applicable to Double and Decimal types');
+        }
+
+        $this->setUpWithTypeAndRangeOpts($type, $rangeOpts);
+
+        $encryptOpts = [
+            'keyId' => $this->key1Id,
+            'algorithm' => ClientEncryption::ALGORITHM_RANGE_PREVIEW,
+            'contentionFactor' => 0,
+            'rangeOpts' => $rangeOpts + ['precision' => 2],
+        ];
+
+        $cast = self::getCastCallableForType($type);
+
+        $this->expectException(EncryptionException::class);
+        $this->expectExceptionMessage('expected \'precision\' to be set with double or decimal128 index');
+        $this->clientEncryption->encrypt($cast(6), $encryptOpts);
+    }
+
+    private function assertMultipleDocumentsMatch(array $expectedDocuments, Iterator $actualDocuments): void
+    {
+        $mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
+        $mi->attachIterator(new ArrayIterator($expectedDocuments));
+        $mi->attachIterator($actualDocuments);
+
+        foreach ($mi as $documents) {
+            [$expectedDocument, $actualDocument] = $documents;
+            $this->assertNotNull($expectedDocument);
+            $this->assertNotNull($actualDocument);
+
+            $this->assertDocumentsMatch($expectedDocument, $actualDocument);
+        }
+    }
+
+    private static function getCastCallableForType(string $type): callable
+    {
+        switch ($type) {
+            case 'DecimalNoPrecision':
+            case 'DecimalPrecision':
+                return function (int $value) {
+                    return new Decimal128((string) $value);
+                };
+
+            case 'DoubleNoPrecision':
+            case 'DoublePrecision':
+                return function (int $value) {
+                    return (double) $value;
+                };
+
+            case 'Date':
+                return function (int $value) {
+                    return new UTCDateTime($value);
+                };
+
+            case 'Int':
+                return function (int $value) {
+                    return $value;
+                };
+
+            case 'Long':
+                return function (int $value) {
+                    return self::createInt64((string) $value);
+                };
+
+            default:
+                throw new LogicException('Unsupported type: ' . $type);
+        }
+    }
+}
diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index a15161aa2..744156fe1 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -4,6 +4,7 @@
 
 use Closure;
 use MongoDB\BSON\Binary;
+use MongoDB\BSON\Document;
 use MongoDB\BSON\Int64;
 use MongoDB\Client;
 use MongoDB\Collection;
@@ -64,202 +65,58 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase
     /** @var array */
     private static $incompleteTests = [
         'explain: Explain a find with deterministic encryption' => 'crypt_shared does not add apiVersion field to explain commands (PHPLIB-947, SERVER-69564)',
-        'fle2v2-Range-Date-Aggregate: FLE2 Range Date. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Delete: FLE2 Range Date. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-FindOneAndUpdate: FLE2 Range Date. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-InsertFind: FLE2 Range Date. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Date-Update: FLE2 Range Date. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Aggregate: FLE2 Range Decimal. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Delete: FLE2 Range Decimal. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-FindOneAndUpdate: FLE2 Range Decimal. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-InsertFind: FLE2 Range Decimal. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Aggregate: FLE2 Range DecimalPrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Delete: FLE2 Range DecimalPrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-FindOneAndUpdate: FLE2 Range DecimalPrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-InsertFind: FLE2 Range DecimalPrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DecimalPrecision-Update: FLE2 Range DecimalPrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Decimal-Update: FLE2 Range Decimal. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Aggregate: FLE2 Range Double. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Delete: FLE2 Range Double. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-FindOneAndUpdate: FLE2 Range Double. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-InsertFind: FLE2 Range Double. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Aggregate: FLE2 Range DoublePrecision. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Wrong type: Insert Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Correctness: Wrong type: Find Int' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Delete: FLE2 Range DoublePrecision. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-FindOneAndUpdate: FLE2 Range DoublePrecision. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-InsertFind: FLE2 Range DoublePrecision. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-DoublePrecision-Update: FLE2 Range DoublePrecision. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Double-Update: FLE2 Range Double. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Aggregate: FLE2 Range Int. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Delete: FLE2 Range Int. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-FindOneAndUpdate: FLE2 Range Int. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-InsertFind: FLE2 Range Int. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Int-Update: FLE2 Range Int. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Aggregate: FLE2 Range Long. Aggregate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $gt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Find with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Insert out of range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Insert min and max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $gte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $gt with no results' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $lte' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $lt below min' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $gt above max' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $gt and $lt' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with equality' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with full range' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Aggregate with $in' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Correctness: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Delete: FLE2 Range Long. Delete.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-FindOneAndUpdate: FLE2 Range Long. FindOneAndUpdate.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-InsertFind: FLE2 Range Long. Insert and Find.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-Long-Update: FLE2 Range Long. Update.' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-WrongType: Wrong type: Insert Double' => 'Not yet implemented (PHPLIB-878)',
-        'fle2v2-Range-WrongType: Wrong type: Find Double' => 'Not yet implemented (PHPLIB-878)',
+        'fle2v2-Range-Decimal-Aggregate: FLE2 Range Decimal. Aggregate.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gt with no results' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $lte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $gt and $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with equality' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Find with $in' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $gte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $gt with no results' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $lte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $gt and $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with equality' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Aggregate with $in' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Wrong type: Insert Int' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Correctness: Wrong type: Find Int' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Delete: FLE2 Range Decimal. Delete.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-FindOneAndUpdate: FLE2 Range Decimal. FindOneAndUpdate.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-InsertFind: FLE2 Range Decimal. Insert and Find.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Aggregate: FLE2 Range DecimalPrecision. Aggregate.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt with no results' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $lt below min' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt above max' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $gt and $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with equality' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with full range' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Find with $in' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Insert out of range' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Insert min and max' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt with no results' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lte' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $lt below min' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt above max' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $gt and $lt' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with equality' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with full range' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Aggregate with $in' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Wrong type: Insert Int' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Correctness: Wrong type: Find Int' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Delete: FLE2 Range DecimalPrecision. Delete.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-FindOneAndUpdate: FLE2 Range DecimalPrecision. FindOneAndUpdate.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-InsertFind: FLE2 Range DecimalPrecision. Insert and Find.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-DecimalPrecision-Update: FLE2 Range DecimalPrecision. Update.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
+        'fle2v2-Range-Decimal-Update: FLE2 Range Decimal. Update.' => 'Bundled libmongocrypt does not support Decimal128 (PHPC-2207)',
         'timeoutMS: timeoutMS applied to listCollections to get collection schema' => 'Not yet implemented (PHPC-1760)',
         'timeoutMS: remaining timeoutMS applied to find to get keyvault data' => 'Not yet implemented (PHPC-1760)',
     ];
@@ -375,8 +232,21 @@ public function provideTests()
         foreach (glob(__DIR__ . '/client-side-encryption/tests/*.json') as $filename) {
             $group = basename($filename, '.json');
 
+            /* Some tests need to differentiate int32 and int64 BSON types.
+             * Decode certain field paths as BSON to preserve type information
+             * that would otherwise be lost by round-tripping through PHP. */
+            $typeMap = [
+                'fieldPaths' => [
+                    'encrypted_fields.fields' => 'bson',
+                    'tests.$.operations.$.arguments.document' => 'bson',
+                    'tests.$.operations.$.arguments.pipeline.$' => 'bson',
+                    'tests.$.operations.$.arguments.filter' => 'bson',
+                    'tests.$.operations.$.arguments.update' => 'bson',
+                ],
+            ];
+
             try {
-                $json = $this->decodeJson(file_get_contents($filename));
+                $json = Document::fromJSON(file_get_contents($filename))->toPHP($typeMap);
             } catch (Throwable $e) {
                 $testArgs[$group] = [
                     (object) ['skipReason' => sprintf('Exception loading file "%s": %s', $filename, $e->getMessage())],
diff --git a/tests/SpecTests/Operation.php b/tests/SpecTests/Operation.php
index eb5c343c7..9d299bd7b 100644
--- a/tests/SpecTests/Operation.php
+++ b/tests/SpecTests/Operation.php
@@ -723,7 +723,7 @@ private function getResultAssertionTypeForCollection()
                     return ResultExpectation::ASSERT_NOTHING;
                 }
 
-                return ResultExpectation::ASSERT_SAME_DOCUMENTS;
+                return ResultExpectation::ASSERT_DOCUMENTS_MATCH;
 
             case 'bulkWrite':
                 return ResultExpectation::ASSERT_BULKWRITE;
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json
deleted file mode 100644
index b0299be2a..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Date.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
-    "fields": [
-        {
-            "keyId": {
-                "$binary": {
-                    "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-                    "subType": "04"
-                }
-            },
-            "path": "encryptedDate",
-            "bsonType": "date",
-            "queries": {
-                "queryType": "rangePreview",
-                "contention": {
-                    "$numberLong": "0"
-                },
-                "sparsity": {
-                    "$numberLong": "1"
-                },
-                "min": {
-                    "$date": {
-                        "$numberLong": "0"
-                    }
-                },
-                "max": {
-                    "$date": {
-                        "$numberLong": "200"
-                    }
-                }
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json
deleted file mode 100644
index 8bd79a15f..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Decimal.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "fields": [
-    {
-      "keyId": {
-        "$binary": {
-          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "path": "encryptedDecimal",
-      "bsonType": "decimal",
-      "queries": {
-        "queryType": "rangePreview",
-        "contention": {
-          "$numberLong": "0"
-        },
-        "sparsity": {
-          "$numberLong": "1"
-        }
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json
deleted file mode 100644
index d52974ef5..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DecimalPrecision.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-  "fields": [
-    {
-      "keyId": {
-        "$binary": {
-          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "path": "encryptedDecimalPrecision",
-      "bsonType": "decimal",
-      "queries": {
-        "queryType": "rangePreview",
-        "contention": {
-          "$numberLong": "0"
-        },
-        "sparsity": {
-          "$numberLong": "1"
-        },
-        "min": {
-          "$numberDecimal": "0.0"
-        },
-        "max": {
-          "$numberDecimal": "200.0"
-        },
-        "precision": {
-          "$numberInt": "2"
-        }
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json
deleted file mode 100644
index 5fbfaa8bd..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Double.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "fields": [
-    {
-      "keyId": {
-        "$binary": {
-          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "path": "encryptedDouble",
-      "bsonType": "double",
-      "queries": {
-        "queryType": "rangePreview",
-        "contention": {
-          "$numberLong": "0"
-        },
-        "sparsity": {
-          "$numberLong": "1"
-        }
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json
deleted file mode 100644
index 18b40d009..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-DoublePrecision.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
-  "fields": [
-    {
-      "keyId": {
-        "$binary": {
-          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "path": "encryptedDoublePrecision",
-      "bsonType": "double",
-      "queries": {
-        "queryType": "rangePreview",
-        "contention": {
-          "$numberLong": "0"
-        },
-        "sparsity": {
-          "$numberLong": "1"
-        },
-        "min": {
-          "$numberDouble": "0.0"
-        },
-        "max": {
-          "$numberDouble": "200.0"
-        },
-        "precision": {
-          "$numberInt": "2"
-        }
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json
deleted file mode 100644
index 819d0b989..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Int.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "fields": [
-    {
-      "keyId": {
-        "$binary": {
-          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "path": "encryptedInt",
-      "bsonType": "int",
-      "queries": {
-        "queryType": "rangePreview",
-        "contention": {
-          "$numberLong": "0"
-        },
-        "sparsity": {
-          "$numberLong": "1"
-        },
-        "min": {
-          "$numberInt": "0"
-        },
-        "max": {
-          "$numberInt": "200"
-        }
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json b/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json
deleted file mode 100644
index c500b85b5..000000000
--- a/tests/SpecTests/client-side-encryption/etc/data/encryptedFields-Range-Long.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-  "fields": [
-    {
-      "keyId": {
-        "$binary": {
-          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-          "subType": "04"
-        }
-      },
-      "path": "encryptedLong",
-      "bsonType": "long",
-      "queries": {
-        "queryType": "rangePreview",
-        "contention": {
-          "$numberLong": "0"
-        },
-        "sparsity": {
-          "$numberLong": "1"
-        },
-        "min": {
-          "$numberLong": "0"
-        },
-        "max": {
-          "$numberLong": "200"
-        }
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json
index e19fc1e18..97a2b2d4e 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Date.json
@@ -1,30 +1,33 @@
 {
-    "fields": [
-      {
-        "keyId": {
-          "$binary": {
-            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-            "subType": "04"
-          }
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDate",
+      "bsonType": "date",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
         },
-        "path": "encryptedDate",
-        "bsonType": "date",
-        "queries": {
-          "queryType": "rangePreview",
-          "sparsity": {
-            "$numberLong": "1"
-          },
-          "min": {
-            "$date": {
-              "$numberLong": "0"
-          }
-          },
-          "max": {
-            "$date": {
-              "$numberLong": "200"
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$date": {
+            "$numberLong": "0"
           }
+        },
+        "max": {
+          "$date": {
+            "$numberLong": "200"
           }
         }
       }
-    ]
+    }
+  ]
 }
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json
index c6d129d4c..4d284475f 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalNoPrecision.json
@@ -1,21 +1,23 @@
 {
-    "fields": [
-      {
-        "keyId": {
-          "$binary": {
-            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-            "subType": "04"
-          }
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDecimalNoPrecision",
+      "bsonType": "decimal",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
         },
-        "path": "encryptedDecimalNoPrecision",
-        "bsonType": "decimal",
-        "queries": {
-          "queryType": "rangePreview",
-          "sparsity": {
-            "$numberInt": "1"
-          }
+        "sparsity": {
+          "$numberLong": "1"
         }
       }
-    ]
-  }
-  
\ No newline at end of file
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json
index c23c3fa92..53449182b 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DecimalPrecision.json
@@ -11,8 +11,11 @@
       "bsonType": "decimal",
       "queries": {
         "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
         "sparsity": {
-          "$numberInt": "1"
+          "$numberLong": "1"
         },
         "min": {
           "$numberDecimal": "0.0"
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json
index 4af642271..b478a772d 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoubleNoPrecision.json
@@ -1,21 +1,23 @@
 {
-    "fields": [
-      {
-        "keyId": {
-          "$binary": {
-            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-            "subType": "04"
-          }
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDoubleNoPrecision",
+      "bsonType": "double",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
         },
-        "path": "encryptedDoubleNoPrecision",
-        "bsonType": "double",
-        "queries": {
-          "queryType": "rangePreview",
-          "sparsity": {
-            "$numberLong": "1"
-          }
+        "sparsity": {
+          "$numberLong": "1"
         }
       }
-    ]
-  }
-  
\ No newline at end of file
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json
index c1f388219..395a36968 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-DoublePrecision.json
@@ -1,30 +1,32 @@
 {
-    "fields": [
-      {
-        "keyId": {
-          "$binary": {
-            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-            "subType": "04"
-          }
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedDoublePrecision",
+      "bsonType": "double",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberDouble": "0.0"
+        },
+        "max": {
+          "$numberDouble": "200.0"
         },
-        "path": "encryptedDoublePrecision",
-        "bsonType": "double",
-        "queries": {
-          "queryType": "rangePreview",
-          "sparsity": {
-            "$numberLong": "1"
-          },
-          "min": {
-            "$numberDouble": "0.0"
-          },
-          "max": {
-            "$numberDouble": "200.0"
-          },
-          "precision": {
-            "$numberInt": "2"
-          }
+        "precision": {
+          "$numberInt": "2"
         }
       }
-    ]
-  }
-  
\ No newline at end of file
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json
index 217bf6743..61b7082df 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Int.json
@@ -1,27 +1,29 @@
 {
-    "fields": [
-      {
-        "keyId": {
-          "$binary": {
-            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-            "subType": "04"
-          }
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedInt",
+      "bsonType": "int",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberInt": "0"
         },
-        "path": "encryptedInt",
-        "bsonType": "int",
-        "queries": {
-          "queryType": "rangePreview",
-          "sparsity": {
-            "$numberLong": "1"
-          },
-          "min": {
-            "$numberInt": "0"
-          },
-          "max": {
-            "$numberInt": "200"
-          }
+        "max": {
+          "$numberInt": "200"
         }
       }
-    ]
-  }
-  
\ No newline at end of file
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json
index 0fb87edae..b18b84b6e 100644
--- a/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json
+++ b/tests/SpecTests/client-side-encryption/etc/data/range-encryptedFields-Long.json
@@ -1,27 +1,29 @@
 {
-    "fields": [
-      {
-        "keyId": {
-          "$binary": {
-            "base64": "EjRWeBI0mHYSNBI0VniQEg==",
-            "subType": "04"
-          }
+  "fields": [
+    {
+      "keyId": {
+        "$binary": {
+          "base64": "EjRWeBI0mHYSNBI0VniQEg==",
+          "subType": "04"
+        }
+      },
+      "path": "encryptedLong",
+      "bsonType": "long",
+      "queries": {
+        "queryType": "rangePreview",
+        "contention": {
+          "$numberLong": "0"
+        },
+        "sparsity": {
+          "$numberLong": "1"
+        },
+        "min": {
+          "$numberLong": "0"
         },
-        "path": "encryptedLong",
-        "bsonType": "long",
-        "queries": {
-          "queryType": "rangePreview",
-          "sparsity": {
-            "$numberLong": "1"
-          },
-          "min": {
-            "$numberLong": "0"
-          },
-          "max": {
-            "$numberLong": "200"
-          }
+        "max": {
+          "$numberLong": "200"
         }
       }
-    ]
-  }
-  
\ No newline at end of file
+    }
+  ]
+}
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
index 529ca57d3..fb129392b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
@@ -20,7 +20,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDecimal",
+        "path": "encryptedDecimalNoPrecision",
         "bsonType": "decimal",
         "queries": {
           "queryType": "rangePreview",
@@ -89,7 +89,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0"
               }
             }
@@ -100,7 +100,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -112,7 +112,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$gt": {
                       "$numberDecimal": "0"
                     }
@@ -124,7 +124,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -183,7 +183,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -203,7 +203,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -230,7 +230,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -250,7 +250,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -277,7 +277,7 @@
               "pipeline": [
                 {
                   "$match": {
-                    "encryptedDecimal": {
+                    "encryptedDecimalNoPrecision": {
                       "$gt": {
                         "$binary": {
                           "base64": "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",
@@ -303,7 +303,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -331,7 +331,7 @@
               "_id": {
                 "$numberInt": "0"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -1115,7 +1115,7 @@
               "_id": {
                 "$numberInt": "1"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
index 5d0436556..5120aecb7 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
@@ -20,7 +20,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDecimal",
+        "path": "encryptedDecimalNoPrecision",
         "bsonType": "decimal",
         "queries": {
           "queryType": "rangePreview",
@@ -89,7 +89,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -100,7 +100,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -110,7 +110,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "0.0"
                 }
@@ -120,7 +120,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -150,7 +150,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -161,7 +161,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -171,7 +171,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gte": {
                   "$numberDecimal": "0.0"
                 }
@@ -184,13 +184,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -220,7 +220,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -231,7 +231,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -241,7 +241,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "1.0"
                 }
@@ -274,7 +274,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -285,7 +285,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -295,7 +295,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$lt": {
                   "$numberDecimal": "1.0"
                 }
@@ -305,7 +305,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -335,7 +335,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -346,7 +346,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -356,7 +356,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$lte": {
                   "$numberDecimal": "1.0"
                 }
@@ -369,13 +369,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -405,7 +405,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -416,7 +416,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -426,7 +426,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "0.0"
                 },
@@ -439,7 +439,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -469,7 +469,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -480,7 +480,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -490,7 +490,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -498,7 +498,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -508,7 +508,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -516,7 +516,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -546,7 +546,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -557,7 +557,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -567,7 +567,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$in": [
                   {
                     "$numberDecimal": "0.0"
@@ -579,7 +579,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -609,7 +609,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -620,7 +620,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -632,7 +632,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$gte": {
                       "$numberDecimal": "0.0"
                     }
@@ -649,13 +649,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -685,7 +685,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -696,7 +696,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -708,7 +708,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$gt": {
                       "$numberDecimal": "1.0"
                     }
@@ -743,7 +743,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -754,7 +754,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -766,7 +766,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$lt": {
                       "$numberDecimal": "1.0"
                     }
@@ -778,7 +778,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -808,7 +808,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -819,7 +819,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -831,7 +831,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$lte": {
                       "$numberDecimal": "1.0"
                     }
@@ -848,13 +848,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -884,7 +884,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -895,7 +895,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -907,7 +907,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$gt": {
                       "$numberDecimal": "0.0"
                     },
@@ -922,7 +922,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -952,7 +952,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -963,7 +963,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -975,7 +975,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$numberDecimal": "0.0"
                   }
                 }
@@ -985,7 +985,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -997,7 +997,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$numberDecimal": "1.0"
                   }
                 }
@@ -1007,7 +1007,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -1037,7 +1037,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -1048,7 +1048,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1.0"
               }
             }
@@ -1060,7 +1060,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$in": [
                       {
                         "$numberDecimal": "0.0"
@@ -1074,7 +1074,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0.0"
               }
             }
@@ -1104,7 +1104,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberInt": "0"
               }
             }
@@ -1136,7 +1136,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gte": {
                   "$numberInt": "0"
                 }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
index c4d855de9..de81159b4 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
@@ -20,7 +20,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDecimal",
+        "path": "encryptedDecimalNoPrecision",
         "bsonType": "decimal",
         "queries": {
           "queryType": "rangePreview",
@@ -89,7 +89,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0"
               }
             }
@@ -100,7 +100,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -110,7 +110,7 @@
           "name": "deleteOne",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "0"
                 }
@@ -174,7 +174,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -194,7 +194,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -221,7 +221,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -241,7 +241,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -268,7 +268,7 @@
               "deletes": [
                 {
                   "q": {
-                    "encryptedDecimal": {
+                    "encryptedDecimalNoPrecision": {
                       "$gt": {
                         "$binary": {
                           "base64": "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",
@@ -295,7 +295,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -323,7 +323,7 @@
               "_id": {
                 "$numberInt": "0"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
index eef729830..36cf91c88 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
@@ -20,7 +20,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDecimal",
+        "path": "encryptedDecimalNoPrecision",
         "bsonType": "decimal",
         "queries": {
           "queryType": "rangePreview",
@@ -89,7 +89,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0"
               }
             }
@@ -100,7 +100,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -110,7 +110,7 @@
           "name": "findOneAndUpdate",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "0"
                 }
@@ -118,7 +118,7 @@
             },
             "update": {
               "$set": {
-                "encryptedDecimal": {
+                "encryptedDecimalNoPrecision": {
                   "$numberDecimal": "2"
                 }
               }
@@ -127,7 +127,7 @@
           },
           "result": {
             "_id": 1,
-            "encryptedDecimal": {
+            "encryptedDecimalNoPrecision": {
               "$numberDecimal": "1"
             }
           }
@@ -185,7 +185,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -205,7 +205,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -232,7 +232,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -252,7 +252,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -277,7 +277,7 @@
             "command": {
               "findAndModify": "default",
               "query": {
-                "encryptedDecimal": {
+                "encryptedDecimalNoPrecision": {
                   "$gt": {
                     "$binary": {
                       "base64": "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",
@@ -288,7 +288,7 @@
               },
               "update": {
                 "$set": {
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -307,7 +307,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -335,7 +335,7 @@
               "_id": {
                 "$numberInt": "0"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -1119,7 +1119,7 @@
               "_id": {
                 "$numberInt": "1"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
index 00a25a558..6b5a642aa 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
@@ -20,7 +20,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDecimal",
+        "path": "encryptedDecimalNoPrecision",
         "bsonType": "decimal",
         "queries": {
           "queryType": "rangePreview",
@@ -89,7 +89,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0"
               }
             }
@@ -100,7 +100,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -110,7 +110,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "0"
                 }
@@ -120,7 +120,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -179,7 +179,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -199,7 +199,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -226,7 +226,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -246,7 +246,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -271,7 +271,7 @@
             "command": {
               "find": "default",
               "filter": {
-                "encryptedDecimal": {
+                "encryptedDecimalNoPrecision": {
                   "$gt": {
                     "$binary": {
                       "base64": "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",
@@ -294,7 +294,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -322,7 +322,7 @@
               "_id": {
                 "$numberInt": "0"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -1106,7 +1106,7 @@
               "_id": {
                 "$numberInt": "1"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
index a9d53fc4f..8cfb7b525 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
@@ -20,7 +20,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDecimal",
+        "path": "encryptedDecimalNoPrecision",
         "bsonType": "decimal",
         "queries": {
           "queryType": "rangePreview",
@@ -89,7 +89,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "0"
               }
             }
@@ -100,7 +100,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$numberDecimal": "1"
               }
             }
@@ -110,7 +110,7 @@
           "name": "updateOne",
           "arguments": {
             "filter": {
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$gt": {
                   "$numberDecimal": "0"
                 }
@@ -118,7 +118,7 @@
             },
             "update": {
               "$set": {
-                "encryptedDecimal": {
+                "encryptedDecimalNoPrecision": {
                   "$numberDecimal": "2"
                 }
               }
@@ -183,7 +183,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -203,7 +203,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -230,7 +230,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDecimal": {
+                  "encryptedDecimalNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -250,7 +250,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -279,7 +279,7 @@
               "updates": [
                 {
                   "q": {
-                    "encryptedDecimal": {
+                    "encryptedDecimalNoPrecision": {
                       "$gt": {
                         "$binary": {
                           "base64": "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",
@@ -290,7 +290,7 @@
                   },
                   "u": {
                     "$set": {
-                      "encryptedDecimal": {
+                      "encryptedDecimalNoPrecision": {
                         "$$type": "binData"
                       }
                     }
@@ -311,7 +311,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDecimal",
+                        "path": "encryptedDecimalNoPrecision",
                         "bsonType": "decimal",
                         "queries": {
                           "queryType": "rangePreview",
@@ -339,7 +339,7 @@
               "_id": {
                 "$numberInt": "0"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -1123,7 +1123,7 @@
               "_id": {
                 "$numberInt": "1"
               },
-              "encryptedDecimal": {
+              "encryptedDecimalNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
index 90882c353..d8c9cacdc 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
@@ -22,7 +22,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDouble",
+        "path": "encryptedDoubleNoPrecision",
         "bsonType": "double",
         "queries": {
           "queryType": "rangePreview",
@@ -91,7 +91,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0"
               }
             }
@@ -102,7 +102,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -114,7 +114,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$gt": {
                       "$numberDouble": "0"
                     }
@@ -126,7 +126,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -185,7 +185,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -205,7 +205,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -232,7 +232,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -252,7 +252,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -279,7 +279,7 @@
               "pipeline": [
                 {
                   "$match": {
-                    "encryptedDouble": {
+                    "encryptedDoubleNoPrecision": {
                       "$gt": {
                         "$binary": {
                           "base64": "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",
@@ -305,7 +305,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -331,7 +331,7 @@
           "data": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -729,7 +729,7 @@
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
index f8e4c5d83..65594bcb1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
@@ -22,7 +22,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDouble",
+        "path": "encryptedDoubleNoPrecision",
         "bsonType": "double",
         "queries": {
           "queryType": "rangePreview",
@@ -91,7 +91,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -102,7 +102,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -112,7 +112,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "0.0"
                 }
@@ -122,7 +122,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -152,7 +152,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -163,7 +163,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -173,7 +173,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gte": {
                   "$numberDouble": "0.0"
                 }
@@ -186,13 +186,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -222,7 +222,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -233,7 +233,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -243,7 +243,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "1.0"
                 }
@@ -276,7 +276,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -287,7 +287,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -297,7 +297,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$lt": {
                   "$numberDouble": "1.0"
                 }
@@ -307,7 +307,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -337,7 +337,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -348,7 +348,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -358,7 +358,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$lte": {
                   "$numberDouble": "1.0"
                 }
@@ -371,13 +371,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -407,7 +407,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -418,7 +418,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -428,7 +428,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "0.0"
                 },
@@ -441,7 +441,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -471,7 +471,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -482,7 +482,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -492,7 +492,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -500,7 +500,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -510,7 +510,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -518,7 +518,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -548,7 +548,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -559,7 +559,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -569,7 +569,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$in": [
                   {
                     "$numberDouble": "0.0"
@@ -581,7 +581,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -611,7 +611,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -622,7 +622,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -634,7 +634,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$gte": {
                       "$numberDouble": "0.0"
                     }
@@ -651,13 +651,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -687,7 +687,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -698,7 +698,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -710,7 +710,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$gt": {
                       "$numberDouble": "1.0"
                     }
@@ -745,7 +745,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -756,7 +756,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -768,7 +768,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$lt": {
                       "$numberDouble": "1.0"
                     }
@@ -780,7 +780,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -810,7 +810,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -821,7 +821,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -833,7 +833,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$lte": {
                       "$numberDouble": "1.0"
                     }
@@ -850,13 +850,13 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -886,7 +886,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -897,7 +897,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -909,7 +909,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$gt": {
                       "$numberDouble": "0.0"
                     },
@@ -924,7 +924,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -954,7 +954,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -965,7 +965,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -977,7 +977,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$numberDouble": "0.0"
                   }
                 }
@@ -987,7 +987,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -999,7 +999,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$numberDouble": "1.0"
                   }
                 }
@@ -1009,7 +1009,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -1039,7 +1039,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -1050,7 +1050,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1.0"
               }
             }
@@ -1062,7 +1062,7 @@
             "pipeline": [
               {
                 "$match": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$in": [
                       {
                         "$numberDouble": "0.0"
@@ -1076,7 +1076,7 @@
           "result": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0.0"
               }
             }
@@ -1106,7 +1106,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberInt": "0"
               }
             }
@@ -1138,7 +1138,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gte": {
                   "$numberInt": "0"
                 }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
index e10e5e0f6..392e722f1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
@@ -22,7 +22,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDouble",
+        "path": "encryptedDoubleNoPrecision",
         "bsonType": "double",
         "queries": {
           "queryType": "rangePreview",
@@ -91,7 +91,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0"
               }
             }
@@ -102,7 +102,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -112,7 +112,7 @@
           "name": "deleteOne",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "0"
                 }
@@ -176,7 +176,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -196,7 +196,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -223,7 +223,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -243,7 +243,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -270,7 +270,7 @@
               "deletes": [
                 {
                   "q": {
-                    "encryptedDouble": {
+                    "encryptedDoubleNoPrecision": {
                       "$gt": {
                         "$binary": {
                           "base64": "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",
@@ -297,7 +297,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -323,7 +323,7 @@
           "data": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
index a29f7948d..bbcfb321f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
@@ -22,7 +22,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDouble",
+        "path": "encryptedDoubleNoPrecision",
         "bsonType": "double",
         "queries": {
           "queryType": "rangePreview",
@@ -91,7 +91,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0"
               }
             }
@@ -102,7 +102,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -112,7 +112,7 @@
           "name": "findOneAndUpdate",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "0"
                 }
@@ -120,7 +120,7 @@
             },
             "update": {
               "$set": {
-                "encryptedDouble": {
+                "encryptedDoubleNoPrecision": {
                   "$numberDouble": "2"
                 }
               }
@@ -129,7 +129,7 @@
           },
           "result": {
             "_id": 1,
-            "encryptedDouble": {
+            "encryptedDoubleNoPrecision": {
               "$numberDouble": "1"
             }
           }
@@ -187,7 +187,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -207,7 +207,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -234,7 +234,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -254,7 +254,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -279,7 +279,7 @@
             "command": {
               "findAndModify": "default",
               "query": {
-                "encryptedDouble": {
+                "encryptedDoubleNoPrecision": {
                   "$gt": {
                     "$binary": {
                       "base64": "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",
@@ -290,7 +290,7 @@
               },
               "update": {
                 "$set": {
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -309,7 +309,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -335,7 +335,7 @@
           "data": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -733,7 +733,7 @@
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
index bee3f58e2..9f2c7c991 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
@@ -22,7 +22,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDouble",
+        "path": "encryptedDoubleNoPrecision",
         "bsonType": "double",
         "queries": {
           "queryType": "rangePreview",
@@ -91,7 +91,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0"
               }
             }
@@ -102,7 +102,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -112,7 +112,7 @@
           "name": "find",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "0"
                 }
@@ -122,7 +122,7 @@
           "result": [
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -181,7 +181,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -201,7 +201,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -228,7 +228,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -248,7 +248,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -273,7 +273,7 @@
             "command": {
               "find": "default",
               "filter": {
-                "encryptedDouble": {
+                "encryptedDoubleNoPrecision": {
                   "$gt": {
                     "$binary": {
                       "base64": "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",
@@ -296,7 +296,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -322,7 +322,7 @@
           "data": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -720,7 +720,7 @@
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
index 1fc605337..ce03576f8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
@@ -22,7 +22,7 @@
             "subType": "04"
           }
         },
-        "path": "encryptedDouble",
+        "path": "encryptedDoubleNoPrecision",
         "bsonType": "double",
         "queries": {
           "queryType": "rangePreview",
@@ -91,7 +91,7 @@
           "arguments": {
             "document": {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "0"
               }
             }
@@ -102,7 +102,7 @@
           "arguments": {
             "document": {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$numberDouble": "1"
               }
             }
@@ -112,7 +112,7 @@
           "name": "updateOne",
           "arguments": {
             "filter": {
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$gt": {
                   "$numberDouble": "0"
                 }
@@ -120,7 +120,7 @@
             },
             "update": {
               "$set": {
-                "encryptedDouble": {
+                "encryptedDoubleNoPrecision": {
                   "$numberDouble": "2"
                 }
               }
@@ -185,7 +185,7 @@
               "documents": [
                 {
                   "_id": 0,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -205,7 +205,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -232,7 +232,7 @@
               "documents": [
                 {
                   "_id": 1,
-                  "encryptedDouble": {
+                  "encryptedDoubleNoPrecision": {
                     "$$type": "binData"
                   }
                 }
@@ -252,7 +252,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -281,7 +281,7 @@
               "updates": [
                 {
                   "q": {
-                    "encryptedDouble": {
+                    "encryptedDoubleNoPrecision": {
                       "$gt": {
                         "$binary": {
                           "base64": "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",
@@ -292,7 +292,7 @@
                   },
                   "u": {
                     "$set": {
-                      "encryptedDouble": {
+                      "encryptedDoubleNoPrecision": {
                         "$$type": "binData"
                       }
                     }
@@ -313,7 +313,7 @@
                             "subType": "04"
                           }
                         },
-                        "path": "encryptedDouble",
+                        "path": "encryptedDoubleNoPrecision",
                         "bsonType": "double",
                         "queries": {
                           "queryType": "rangePreview",
@@ -339,7 +339,7 @@
           "data": [
             {
               "_id": 0,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [
@@ -737,7 +737,7 @@
             },
             {
               "_id": 1,
-              "encryptedDouble": {
+              "encryptedDoubleNoPrecision": {
                 "$$type": "binData"
               },
               "__safeContent__": [

From b4909e8a69c66322f21070c8d5aa5b17a1c7fdb4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 1 Jun 2023 11:54:00 +0200
Subject: [PATCH 294/321] PHPLIB-1117: Remove @api annotation (#1087)

* Setup rector
* Remove api annotation, all classes are public by default unless marked with internal
---
 CONTRIBUTING.md                          | 11 +++++++++++
 composer.json                            |  6 ++++--
 rector.php                               | 23 +++++++++++++++++++++++
 src/ChangeStream.php                     |  5 ++---
 src/GridFS/Bucket.php                    |  2 --
 src/MapReduceResult.php                  |  1 -
 src/Model/BSONArray.php                  |  2 --
 src/Model/BSONDocument.php               |  2 --
 src/Model/CollectionInfo.php             |  1 -
 src/Model/CollectionInfoIterator.php     |  1 -
 src/Model/DatabaseInfo.php               |  1 -
 src/Model/DatabaseInfoIterator.php       |  1 -
 src/Model/IndexInfo.php                  |  1 -
 src/Model/IndexInfoIterator.php          |  1 -
 src/Operation/Aggregate.php              |  1 -
 src/Operation/BulkWrite.php              |  1 -
 src/Operation/Count.php                  |  1 -
 src/Operation/CountDocuments.php         |  1 -
 src/Operation/CreateCollection.php       |  1 -
 src/Operation/CreateIndexes.php          |  1 -
 src/Operation/DatabaseCommand.php        |  1 -
 src/Operation/DeleteMany.php             |  1 -
 src/Operation/DeleteOne.php              |  1 -
 src/Operation/Distinct.php               |  1 -
 src/Operation/DropCollection.php         |  1 -
 src/Operation/DropDatabase.php           |  1 -
 src/Operation/DropIndexes.php            |  1 -
 src/Operation/EstimatedDocumentCount.php |  1 -
 src/Operation/Explain.php                |  1 -
 src/Operation/Find.php                   |  1 -
 src/Operation/FindOne.php                |  1 -
 src/Operation/FindOneAndDelete.php       |  1 -
 src/Operation/FindOneAndReplace.php      |  1 -
 src/Operation/FindOneAndUpdate.php       |  1 -
 src/Operation/InsertMany.php             |  1 -
 src/Operation/InsertOne.php              |  1 -
 src/Operation/ListCollectionNames.php    |  1 -
 src/Operation/ListCollections.php        |  1 -
 src/Operation/ListDatabaseNames.php      |  1 -
 src/Operation/ListDatabases.php          |  1 -
 src/Operation/ListIndexes.php            |  1 -
 src/Operation/MapReduce.php              |  1 -
 src/Operation/ModifyCollection.php       |  1 -
 src/Operation/RenameCollection.php       |  1 -
 src/Operation/ReplaceOne.php             |  1 -
 src/Operation/UpdateMany.php             |  1 -
 src/Operation/UpdateOne.php              |  1 -
 src/Operation/Watch.php                  |  1 -
 48 files changed, 40 insertions(+), 52 deletions(-)
 create mode 100644 rector.php

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 892db70c7..7e9e46404 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -151,6 +151,17 @@ possible it can be added to the baseline using `set-baseline`:
 $ vendor/bin/psalm --set-baseline=psalm-baseline.xml
 ```
 
+## Automatic code refactoring
+
+The library uses [rector](https://getrector.com/) to refactor the code for new features.
+To run automatic refactoring, use the `rector` command:
+
+```
+$ vendor/bin/rector
+```
+
+New rules can be added to the `rector.php` configuration file.
+
 ## Documentation
 
 Documentation for the library lives in the `docs/` directory and is built with
diff --git a/composer.json b/composer.json
index e9ee7edae..772723852 100644
--- a/composer.json
+++ b/composer.json
@@ -18,8 +18,9 @@
         "symfony/polyfill-php80": "^1.27"
     },
     "require-dev": {
-        "squizlabs/php_codesniffer": "^3.7",
         "doctrine/coding-standard": "^11.1",
+        "rector/rector": "^0.16.0",
+        "squizlabs/php_codesniffer": "^3.7",
         "symfony/phpunit-bridge": "^5.2",
         "vimeo/psalm": "^4.28"
     },
@@ -39,6 +40,7 @@
     "config": {
         "allow-plugins": {
             "dealerdirect/phpcodesniffer-composer-installer": true
-        }
+        },
+        "sort-packages": true
     }
 }
diff --git a/rector.php b/rector.php
new file mode 100644
index 000000000..08029a4d8
--- /dev/null
+++ b/rector.php
@@ -0,0 +1,23 @@
+paths([
+        __DIR__ . '/examples',
+        __DIR__ . '/src',
+        __DIR__ . '/tests',
+        __DIR__ . '/tools',
+    ]);
+
+    /**
+     * All classes are public API by default, unless marked with @internal.
+     */
+    $rectorConfig->ruleWithConfiguration(RemoveAnnotationRector::class, ['api']);
+
+    // define sets of rules
+    //    $rectorConfig->sets([
+    //        LevelSetList::UP_TO_PHP_72
+    //    ]);
+};
diff --git a/src/ChangeStream.php b/src/ChangeStream.php
index e824b87d9..628a9886c 100644
--- a/src/ChangeStream.php
+++ b/src/ChangeStream.php
@@ -33,11 +33,10 @@
 /**
  * Iterator for a change stream.
  *
- * @psalm-type ResumeCallable = callable(array|object|null, bool): ChangeStreamIterator
- *
- * @api
  * @see \MongoDB\Collection::watch()
  * @see https://mongodb.com/docs/manual/reference/method/db.watch/#mongodb-method-db.watch
+ *
+ * @psalm-type ResumeCallable = callable(array|object|null, bool): ChangeStreamIterator
  */
 class ChangeStream implements Iterator
 {
diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php
index 259b35608..a9acf8a52 100644
--- a/src/GridFS/Bucket.php
+++ b/src/GridFS/Bucket.php
@@ -59,8 +59,6 @@
 /**
  * Bucket provides a public API for interacting with the GridFS files and chunks
  * collections.
- *
- * @api
  */
 class Bucket
 {
diff --git a/src/MapReduceResult.php b/src/MapReduceResult.php
index d7ef777a3..4c70b4a07 100644
--- a/src/MapReduceResult.php
+++ b/src/MapReduceResult.php
@@ -31,7 +31,6 @@
  * output method (e.g. inline, collection) via the IteratorAggregate interface.
  * It also provides access to command statistics.
  *
- * @api
  * @see \MongoDB\Collection::mapReduce()
  * @see https://mongodb.com/docs/manual/reference/command/mapReduce/
  */
diff --git a/src/Model/BSONArray.php b/src/Model/BSONArray.php
index a87505f29..c10d05faf 100644
--- a/src/Model/BSONArray.php
+++ b/src/Model/BSONArray.php
@@ -31,8 +31,6 @@
  *
  * The internal data will be filtered through array_values() during BSON
  * serialization to ensure that it becomes a BSON array.
- *
- * @api
  */
 class BSONArray extends ArrayObject implements JsonSerializable, Serializable, Unserializable
 {
diff --git a/src/Model/BSONDocument.php b/src/Model/BSONDocument.php
index 8fc04e84f..56b7787bb 100644
--- a/src/Model/BSONDocument.php
+++ b/src/Model/BSONDocument.php
@@ -30,8 +30,6 @@
  *
  * The internal data will be cast to an object during BSON serialization to
  * ensure that it becomes a BSON document.
- *
- * @api
  */
 class BSONDocument extends ArrayObject implements JsonSerializable, Serializable, Unserializable
 {
diff --git a/src/Model/CollectionInfo.php b/src/Model/CollectionInfo.php
index f7ab95846..4940a5e00 100644
--- a/src/Model/CollectionInfo.php
+++ b/src/Model/CollectionInfo.php
@@ -30,7 +30,6 @@
  * command or, for legacy servers, queries on the "system.namespaces"
  * collection. It provides methods to access options for the collection.
  *
- * @api
  * @see \MongoDB\Database::listCollections()
  * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-collections.rst
  */
diff --git a/src/Model/CollectionInfoIterator.php b/src/Model/CollectionInfoIterator.php
index aa6cb3afb..87315d20a 100644
--- a/src/Model/CollectionInfoIterator.php
+++ b/src/Model/CollectionInfoIterator.php
@@ -25,7 +25,6 @@
  *
  * This iterator is used for enumerating collections in a database.
  *
- * @api
  * @see \MongoDB\Database::listCollections()
  */
 interface CollectionInfoIterator extends Iterator
diff --git a/src/Model/DatabaseInfo.php b/src/Model/DatabaseInfo.php
index f09d9a129..062600784 100644
--- a/src/Model/DatabaseInfo.php
+++ b/src/Model/DatabaseInfo.php
@@ -29,7 +29,6 @@
  * This class models the database information returned by the listDatabases
  * command. It provides methods to access common database properties.
  *
- * @api
  * @see \MongoDB\Client::listDatabases()
  * @see https://mongodb.com/docs/manual/reference/command/listDatabases/
  */
diff --git a/src/Model/DatabaseInfoIterator.php b/src/Model/DatabaseInfoIterator.php
index cb6135750..e135de368 100644
--- a/src/Model/DatabaseInfoIterator.php
+++ b/src/Model/DatabaseInfoIterator.php
@@ -25,7 +25,6 @@
  *
  * This iterator is used for enumerating databases on a server.
  *
- * @api
  * @see \MongoDB\Client::listDatabases()
  */
 interface DatabaseInfoIterator extends Iterator
diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php
index 590d1640e..ce4b2af8a 100644
--- a/src/Model/IndexInfo.php
+++ b/src/Model/IndexInfo.php
@@ -34,7 +34,6 @@
  * For information on keys and index options, see the referenced
  * db.collection.createIndex() documentation.
  *
- * @api
  * @see \MongoDB\Collection::listIndexes()
  * @see https://github.com/mongodb/specifications/blob/master/source/enumerate-indexes.rst
  * @see https://mongodb.com/docs/manual/reference/method/db.collection.createIndex/
diff --git a/src/Model/IndexInfoIterator.php b/src/Model/IndexInfoIterator.php
index 342fac6a8..26e2d3d30 100644
--- a/src/Model/IndexInfoIterator.php
+++ b/src/Model/IndexInfoIterator.php
@@ -25,7 +25,6 @@
  *
  * This iterator is used for enumerating indexes in a collection.
  *
- * @api
  * @see \MongoDB\Collection::listIndexes()
  */
 interface IndexInfoIterator extends Iterator
diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php
index 5b278cdd2..b3d01f5ed 100644
--- a/src/Operation/Aggregate.php
+++ b/src/Operation/Aggregate.php
@@ -44,7 +44,6 @@
 /**
  * Operation for the aggregate command.
  *
- * @api
  * @see \MongoDB\Collection::aggregate()
  * @see https://mongodb.com/docs/manual/reference/command/aggregate/
  */
diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php
index 28568de25..2296007dd 100644
--- a/src/Operation/BulkWrite.php
+++ b/src/Operation/BulkWrite.php
@@ -40,7 +40,6 @@
 /**
  * Operation for executing multiple write operations.
  *
- * @api
  * @see \MongoDB\Collection::bulkWrite()
  */
 class BulkWrite implements Executable
diff --git a/src/Operation/Count.php b/src/Operation/Count.php
index 251ba900a..9234825f8 100644
--- a/src/Operation/Count.php
+++ b/src/Operation/Count.php
@@ -37,7 +37,6 @@
 /**
  * Operation for the count command.
  *
- * @api
  * @see \MongoDB\Collection::count()
  * @see https://mongodb.com/docs/manual/reference/command/count/
  */
diff --git a/src/Operation/CountDocuments.php b/src/Operation/CountDocuments.php
index 57b04544b..d83a6bd6e 100644
--- a/src/Operation/CountDocuments.php
+++ b/src/Operation/CountDocuments.php
@@ -36,7 +36,6 @@
 /**
  * Operation for obtaining an exact count of documents in a collection
  *
- * @api
  * @see \MongoDB\Collection::countDocuments()
  * @see https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst#countdocuments
  */
diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php
index 12aaa3dbb..a4cc721c0 100644
--- a/src/Operation/CreateCollection.php
+++ b/src/Operation/CreateCollection.php
@@ -38,7 +38,6 @@
 /**
  * Operation for the create command.
  *
- * @api
  * @see \MongoDB\Database::createCollection()
  * @see https://mongodb.com/docs/manual/reference/command/create/
  */
diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php
index 351f25116..3346c84ed 100644
--- a/src/Operation/CreateIndexes.php
+++ b/src/Operation/CreateIndexes.php
@@ -36,7 +36,6 @@
 /**
  * Operation for the createIndexes command.
  *
- * @api
  * @see \MongoDB\Collection::createIndex()
  * @see \MongoDB\Collection::createIndexes()
  * @see https://mongodb.com/docs/manual/reference/command/createIndexes/
diff --git a/src/Operation/DatabaseCommand.php b/src/Operation/DatabaseCommand.php
index 4e6fac522..7c989ae07 100644
--- a/src/Operation/DatabaseCommand.php
+++ b/src/Operation/DatabaseCommand.php
@@ -30,7 +30,6 @@
 /**
  * Operation for executing a database command.
  *
- * @api
  * @see \MongoDB\Database::command()
  */
 class DatabaseCommand implements Executable
diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php
index 33497f3f4..3d17daeba 100644
--- a/src/Operation/DeleteMany.php
+++ b/src/Operation/DeleteMany.php
@@ -26,7 +26,6 @@
 /**
  * Operation for deleting multiple document with the delete command.
  *
- * @api
  * @see \MongoDB\Collection::deleteOne()
  * @see https://mongodb.com/docs/manual/reference/command/delete/
  */
diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php
index a91d67bb5..d048741ad 100644
--- a/src/Operation/DeleteOne.php
+++ b/src/Operation/DeleteOne.php
@@ -26,7 +26,6 @@
 /**
  * Operation for deleting a single document with the delete command.
  *
- * @api
  * @see \MongoDB\Collection::deleteOne()
  * @see https://mongodb.com/docs/manual/reference/command/delete/
  */
diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php
index a249adf71..89f3faee5 100644
--- a/src/Operation/Distinct.php
+++ b/src/Operation/Distinct.php
@@ -36,7 +36,6 @@
 /**
  * Operation for the distinct command.
  *
- * @api
  * @see \MongoDB\Collection::distinct()
  * @see https://mongodb.com/docs/manual/reference/command/distinct/
  */
diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php
index 11e85bdd7..0c67c1918 100644
--- a/src/Operation/DropCollection.php
+++ b/src/Operation/DropCollection.php
@@ -32,7 +32,6 @@
 /**
  * Operation for the drop command.
  *
- * @api
  * @see \MongoDB\Collection::drop()
  * @see \MongoDB\Database::dropCollection()
  * @see https://mongodb.com/docs/manual/reference/command/drop/
diff --git a/src/Operation/DropDatabase.php b/src/Operation/DropDatabase.php
index c909b2436..e207c96de 100644
--- a/src/Operation/DropDatabase.php
+++ b/src/Operation/DropDatabase.php
@@ -30,7 +30,6 @@
 /**
  * Operation for the dropDatabase command.
  *
- * @api
  * @see \MongoDB\Client::dropDatabase()
  * @see \MongoDB\Database::drop()
  * @see https://mongodb.com/docs/manual/reference/command/dropDatabase/
diff --git a/src/Operation/DropIndexes.php b/src/Operation/DropIndexes.php
index ef0e2f4d3..915fbe5a9 100644
--- a/src/Operation/DropIndexes.php
+++ b/src/Operation/DropIndexes.php
@@ -32,7 +32,6 @@
 /**
  * Operation for the dropIndexes command.
  *
- * @api
  * @see \MongoDB\Collection::dropIndexes()
  * @see https://mongodb.com/docs/manual/reference/command/dropIndexes/
  */
diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php
index dc91a27ac..e6fa6b02a 100644
--- a/src/Operation/EstimatedDocumentCount.php
+++ b/src/Operation/EstimatedDocumentCount.php
@@ -32,7 +32,6 @@
 /**
  * Operation for obtaining an estimated count of documents in a collection
  *
- * @api
  * @see \MongoDB\Collection::estimatedDocumentCount()
  * @see https://mongodb.com/docs/manual/reference/command/count/
  */
diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php
index cc59670e4..1ab9d3816 100644
--- a/src/Operation/Explain.php
+++ b/src/Operation/Explain.php
@@ -33,7 +33,6 @@
 /**
  * Operation for the explain command.
  *
- * @api
  * @see \MongoDB\Collection::explain()
  * @see https://mongodb.com/docs/manual/reference/command/explain/
  */
diff --git a/src/Operation/Find.php b/src/Operation/Find.php
index ca91cb94c..a2e25b8a5 100644
--- a/src/Operation/Find.php
+++ b/src/Operation/Find.php
@@ -40,7 +40,6 @@
 /**
  * Operation for the find command.
  *
- * @api
  * @see \MongoDB\Collection::find()
  * @see https://mongodb.com/docs/manual/tutorial/query-documents/
  * @see https://mongodb.com/docs/manual/reference/operator/query-modifier/
diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php
index 3de70dae6..b70443c83 100644
--- a/src/Operation/FindOne.php
+++ b/src/Operation/FindOne.php
@@ -27,7 +27,6 @@
 /**
  * Operation for finding a single document with the find command.
  *
- * @api
  * @see \MongoDB\Collection::findOne()
  * @see https://mongodb.com/docs/manual/tutorial/query-documents/
  * @see https://mongodb.com/docs/manual/reference/operator/query-modifier/
diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php
index c4b54dadf..7ce9ee7c4 100644
--- a/src/Operation/FindOneAndDelete.php
+++ b/src/Operation/FindOneAndDelete.php
@@ -28,7 +28,6 @@
 /**
  * Operation for deleting a document with the findAndModify command.
  *
- * @api
  * @see \MongoDB\Collection::findOneAndDelete()
  * @see https://mongodb.com/docs/manual/reference/command/findAndModify/
  */
diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php
index 0e619b86d..46b0bd5d3 100644
--- a/src/Operation/FindOneAndReplace.php
+++ b/src/Operation/FindOneAndReplace.php
@@ -31,7 +31,6 @@
 /**
  * Operation for replacing a document with the findAndModify command.
  *
- * @api
  * @see \MongoDB\Collection::findOneAndReplace()
  * @see https://mongodb.com/docs/manual/reference/command/findAndModify/
  */
diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php
index e9a592473..adc0ae24c 100644
--- a/src/Operation/FindOneAndUpdate.php
+++ b/src/Operation/FindOneAndUpdate.php
@@ -32,7 +32,6 @@
 /**
  * Operation for updating a document with the findAndModify command.
  *
- * @api
  * @see \MongoDB\Collection::findOneAndUpdate()
  * @see https://mongodb.com/docs/manual/reference/command/findAndModify/
  */
diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php
index b8b3c1255..816315dcd 100644
--- a/src/Operation/InsertMany.php
+++ b/src/Operation/InsertMany.php
@@ -34,7 +34,6 @@
 /**
  * Operation for inserting multiple documents with the insert command.
  *
- * @api
  * @see \MongoDB\Collection::insertMany()
  * @see https://mongodb.com/docs/manual/reference/command/insert/
  */
diff --git a/src/Operation/InsertOne.php b/src/Operation/InsertOne.php
index d0690a5d5..0d32530e6 100644
--- a/src/Operation/InsertOne.php
+++ b/src/Operation/InsertOne.php
@@ -33,7 +33,6 @@
 /**
  * Operation for inserting a single document with the insert command.
  *
- * @api
  * @see \MongoDB\Collection::insertOne()
  * @see https://mongodb.com/docs/manual/reference/command/insert/
  */
diff --git a/src/Operation/ListCollectionNames.php b/src/Operation/ListCollectionNames.php
index d0700887b..ebfa5977b 100644
--- a/src/Operation/ListCollectionNames.php
+++ b/src/Operation/ListCollectionNames.php
@@ -27,7 +27,6 @@
 /**
  * Operation for the listCollectionNames helper.
  *
- * @api
  * @see \MongoDB\Database::listCollectionNames()
  * @see https://mongodb.com/docs/manual/reference/command/listCollections/
  */
diff --git a/src/Operation/ListCollections.php b/src/Operation/ListCollections.php
index e5702509b..a46968983 100644
--- a/src/Operation/ListCollections.php
+++ b/src/Operation/ListCollections.php
@@ -27,7 +27,6 @@
 /**
  * Operation for the listCollections command.
  *
- * @api
  * @see \MongoDB\Database::listCollections()
  * @see https://mongodb.com/docs/manual/reference/command/listCollections/
  */
diff --git a/src/Operation/ListDatabaseNames.php b/src/Operation/ListDatabaseNames.php
index ccace38f8..db2a468cd 100644
--- a/src/Operation/ListDatabaseNames.php
+++ b/src/Operation/ListDatabaseNames.php
@@ -30,7 +30,6 @@
 /**
  * Operation for the ListDatabases command, returning only database names.
  *
- * @api
  * @see \MongoDB\Client::listDatabaseNames()
  * @see https://mongodb.com/docs/manual/reference/command/listDatabases/#mongodb-dbcommand-dbcmd.listDatabases
  */
diff --git a/src/Operation/ListDatabases.php b/src/Operation/ListDatabases.php
index a19cf07bb..412538c16 100644
--- a/src/Operation/ListDatabases.php
+++ b/src/Operation/ListDatabases.php
@@ -28,7 +28,6 @@
 /**
  * Operation for the ListDatabases command.
  *
- * @api
  * @see \MongoDB\Client::listDatabases()
  * @see https://mongodb.com/docs/manual/reference/command/listDatabases/#mongodb-dbcommand-dbcmd.listDatabases`
  */
diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php
index e762d9ca2..3dca9833f 100644
--- a/src/Operation/ListIndexes.php
+++ b/src/Operation/ListIndexes.php
@@ -33,7 +33,6 @@
 /**
  * Operation for the listIndexes command.
  *
- * @api
  * @see \MongoDB\Collection::listIndexes()
  * @see https://mongodb.com/docs/manual/reference/command/listIndexes/
  */
diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php
index 7f19f143b..b02dc8142 100644
--- a/src/Operation/MapReduce.php
+++ b/src/Operation/MapReduce.php
@@ -48,7 +48,6 @@
 /**
  * Operation for the mapReduce command.
  *
- * @api
  * @see \MongoDB\Collection::mapReduce()
  * @see https://mongodb.com/docs/manual/reference/command/mapReduce/
  */
diff --git a/src/Operation/ModifyCollection.php b/src/Operation/ModifyCollection.php
index 7933859bf..61b5aafe6 100644
--- a/src/Operation/ModifyCollection.php
+++ b/src/Operation/ModifyCollection.php
@@ -30,7 +30,6 @@
 /**
  * Operation for the collMod command.
  *
- * @api
  * @see \MongoDB\Database::modifyCollection()
  * @see https://mongodb.com/docs/manual/reference/command/collMod/
  */
diff --git a/src/Operation/RenameCollection.php b/src/Operation/RenameCollection.php
index 64758b0a7..5ab7a6f20 100644
--- a/src/Operation/RenameCollection.php
+++ b/src/Operation/RenameCollection.php
@@ -32,7 +32,6 @@
 /**
  * Operation for the renameCollection command.
  *
- * @api
  * @see \MongoDB\Collection::rename()
  * @see \MongoDB\Database::renameCollection()
  * @see https://mongodb.com/docs/manual/reference/command/renameCollection/
diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php
index d5d117b91..ce794f9c7 100644
--- a/src/Operation/ReplaceOne.php
+++ b/src/Operation/ReplaceOne.php
@@ -31,7 +31,6 @@
 /**
  * Operation for replacing a single document with the update command.
  *
- * @api
  * @see \MongoDB\Collection::replaceOne()
  * @see https://mongodb.com/docs/manual/reference/command/update/
  */
diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php
index e442365a1..b751c1c51 100644
--- a/src/Operation/UpdateMany.php
+++ b/src/Operation/UpdateMany.php
@@ -31,7 +31,6 @@
 /**
  * Operation for updating multiple documents with the update command.
  *
- * @api
  * @see \MongoDB\Collection::updateMany()
  * @see https://mongodb.com/docs/manual/reference/command/update/
  */
diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php
index a7bfab518..ab57defbc 100644
--- a/src/Operation/UpdateOne.php
+++ b/src/Operation/UpdateOne.php
@@ -31,7 +31,6 @@
 /**
  * Operation for updating a single document with the update command.
  *
- * @api
  * @see \MongoDB\Collection::updateOne()
  * @see https://mongodb.com/docs/manual/reference/command/update/
  */
diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php
index 9306a5312..2e6bf00c0 100644
--- a/src/Operation/Watch.php
+++ b/src/Operation/Watch.php
@@ -53,7 +53,6 @@
  * Note: the implementation of CommandSubscriber is an internal implementation
  * detail and should not be considered part of the public API.
  *
- * @api
  * @see \MongoDB\Collection::watch()
  * @see https://mongodb.com/docs/manual/changeStreams/
  */

From 9d4e7b8e2ce813a129bae1781d56112fece3ac1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 1 Jun 2023 12:44:52 +0200
Subject: [PATCH 295/321] PHPLIB-1141: Setup rector in CI (#1088)

* Setup rector config
* Setup rector in CI
* Merge rector into static analysis job
* Disable bugged rules
* Fix BucketFunctionalTest::testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToExist
---
 .github/workflows/static-analysis.yml         |  3 +++
 examples/aggregate.php                        |  4 +--
 phpcs.xml.dist                                |  1 +
 rector.php                                    | 26 +++++++++++++------
 tests/FunctionsTest.php                       |  8 +++---
 tests/GridFS/BucketFunctionalTest.php         |  2 +-
 tests/GridFS/UnusableStream.php               |  2 +-
 tests/Operation/WatchFunctionalTest.php       |  3 +--
 tests/UnifiedSpecTests/Constraint/Matches.php |  1 +
 9 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index ef1a2c0ba..5b0840407 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -65,3 +65,6 @@ jobs:
 
       - name: "Run Psalm"
         run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)"
+
+      - name: "Run Rector"
+        run: "vendor/bin/rector --ansi --dry-run"
diff --git a/examples/aggregate.php b/examples/aggregate.php
index 7f9da6cc3..d1ee69450 100644
--- a/examples/aggregate.php
+++ b/examples/aggregate.php
@@ -11,7 +11,7 @@
 use function MongoDB\BSON\fromPHP;
 use function MongoDB\BSON\toRelaxedExtendedJSON;
 use function printf;
-use function rand;
+use function random_int;
 
 require __DIR__ . '/../vendor/autoload.php';
 
@@ -28,7 +28,7 @@ function toJSON(object $document): string
 $documents = [];
 
 for ($i = 0; $i < 100; $i++) {
-    $documents[] = ['randomValue' => rand(0, 1000)];
+    $documents[] = ['randomValue' => random_int(0, 1000)];
 }
 
 $collection->insertMany($documents);
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 02b0fd035..a4dee252f 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -13,6 +13,7 @@
     examples
     tests
     tools
+    rector.php
 
     
     
diff --git a/rector.php b/rector.php
index 08029a4d8..cf5d60690 100644
--- a/rector.php
+++ b/rector.php
@@ -2,6 +2,9 @@
 
 use Rector\Config\RectorConfig;
 use Rector\DeadCode\Rector\ClassLike\RemoveAnnotationRector;
+use Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector;
+use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector;
+use Rector\Set\ValueObject\LevelSetList;
 
 return static function (RectorConfig $rectorConfig): void {
     $rectorConfig->paths([
@@ -11,13 +14,20 @@
         __DIR__ . '/tools',
     ]);
 
-    /**
-     * All classes are public API by default, unless marked with @internal.
-     */
-    $rectorConfig->ruleWithConfiguration(RemoveAnnotationRector::class, ['api']);
+    // Modernize code
+    $rectorConfig->sets([LevelSetList::UP_TO_PHP_72]);
+
+    $rectorConfig->skip([
+        // Falsely detect unassigned variables in code paths stopped by PHPUnit\Framework\Assert::markTestSkipped()
+        AddDefaultValueForUndefinedVariableRector::class => [
+            __DIR__ . '/tests/',
+        ],
+        // @see https://github.com/phpstan/phpstan-src/pull/2429
+        RemoveExtraParametersRector::class => [
+            __DIR__ . '/src/Operation/',
+        ],
+    ]);
 
-    // define sets of rules
-    //    $rectorConfig->sets([
-    //        LevelSetList::UP_TO_PHP_72
-    //    ]);
+    // All classes are public API by default, unless marked with @internal.
+    $rectorConfig->ruleWithConfiguration(RemoveAnnotationRector::class, ['api']);
 };
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index 167cbe291..5f1170265 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -210,7 +210,7 @@ public function provideTypeMapValues()
             'Array field path converted to array' => [
                 [
                     'root' => 'object',
-                    'array' => 'MongoDB\Model\BSONArray',
+                    'array' => BSONArray::class,
                     'fieldPaths' => [
                         'field' => 'array',
                         'field.$' => 'object',
@@ -219,7 +219,7 @@ public function provideTypeMapValues()
                 ],
                 [
                     'root' => 'object',
-                    'array' => 'MongoDB\Model\BSONArray',
+                    'array' => BSONArray::class,
                     'fieldPaths' => ['nested' => 'array'],
                 ],
                 'field.$',
@@ -227,14 +227,14 @@ public function provideTypeMapValues()
             'Array field path without root key' => [
                 [
                     'root' => 'object',
-                    'array' => 'MongoDB\Model\BSONArray',
+                    'array' => BSONArray::class,
                     'fieldPaths' => [
                         'field' => 'array',
                         'field.$.nested' => 'array',
                     ],
                 ],
                 [
-                    'array' => 'MongoDB\Model\BSONArray',
+                    'array' => BSONArray::class,
                     'fieldPaths' => ['nested' => 'array'],
                 ],
                 'field.$',
diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php
index 97eb7317d..dbdfe2017 100644
--- a/tests/GridFS/BucketFunctionalTest.php
+++ b/tests/GridFS/BucketFunctionalTest.php
@@ -549,7 +549,7 @@ public function testOpenDownloadStreamByNameShouldRequireFilenameAndRevisionToEx
         $this->bucket->uploadFromStream('filename', $this->createStream('bar'));
 
         $this->expectException(FileNotFoundException::class);
-        $this->bucket->openDownloadStream($filename, ['revision' => $revision]);
+        $this->bucket->openDownloadStreamByName($filename, ['revision' => $revision]);
     }
 
     public function testOpenUploadStream(): void
diff --git a/tests/GridFS/UnusableStream.php b/tests/GridFS/UnusableStream.php
index c7686638b..34e964da4 100644
--- a/tests/GridFS/UnusableStream.php
+++ b/tests/GridFS/UnusableStream.php
@@ -20,7 +20,7 @@ public static function register($protocol = 'unusable'): void
             stream_wrapper_unregister($protocol);
         }
 
-        stream_wrapper_register($protocol, static::class, STREAM_IS_URL);
+        stream_wrapper_register($protocol, self::class, STREAM_IS_URL);
     }
 
     public function stream_close(): void
diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php
index cae3d850a..aefadcb56 100644
--- a/tests/Operation/WatchFunctionalTest.php
+++ b/tests/Operation/WatchFunctionalTest.php
@@ -1107,8 +1107,7 @@ public function testResumeTokenNotFoundDoesNotAdvanceKey(): void
         try {
             $changeStream->next();
             $this->fail('Exception for missing resume token was not thrown');
-        } catch (ResumeTokenException $e) {
-        } catch (ServerException $e) {
+        } catch (ResumeTokenException | ServerException $e) {
         }
 
         $this->assertFalse($changeStream->valid());
diff --git a/tests/UnifiedSpecTests/Constraint/Matches.php b/tests/UnifiedSpecTests/Constraint/Matches.php
index eea67a153..579240d69 100644
--- a/tests/UnifiedSpecTests/Constraint/Matches.php
+++ b/tests/UnifiedSpecTests/Constraint/Matches.php
@@ -368,6 +368,7 @@ private function doToString()
         return 'matches ' . $this->exporter()->export($this->value);
     }
 
+    /** @psalm-return never-return */
     private static function failAt(string $message, string $keyPath): void
     {
         $prefix = empty($keyPath) ? '' : sprintf('Field path "%s": ', $keyPath);

From f6551edd60a368f019bb7cd1dda4fe78a5e7597b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 1 Jun 2023 16:28:18 +0200
Subject: [PATCH 296/321] DRIVERS-448: Remove documentation example that used
 collStats (#1091)

https://jira.mongodb.org/browse/DRIVERS-448
---
 tests/DocumentationExamplesTest.php | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index 0d512b3b5..096edeea9 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -1190,20 +1190,6 @@ public function testRunCommand_example_1(): void
         $this->assertInstanceOf(Cursor::class, $cursor);
     }
 
-    public function testRunCommand_example_2(): void
-    {
-        $db = new Database($this->manager, $this->getDatabaseName());
-        $db->dropCollection('restaurants');
-        $db->createCollection('restaurants');
-
-        // Start runCommand Example 2
-        $cursor = $db->command(['collStats' => 'restaurants']);
-        $result = $cursor->toArray()[0];
-        // End runCommand Example 2
-
-        $this->assertInstanceOf(Cursor::class, $cursor);
-    }
-
     public function testIndex_example_1(): void
     {
         $db = new Database($this->manager, $this->getDatabaseName());

From 7b463d76b179eb13a589a7f86cae44a2c27d48e8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 1 Jun 2023 16:52:54 +0200
Subject: [PATCH 297/321] PHPLIB-475: Use ReadPreference string constant
 consistently in the code and the doc (#1082)

* ReadPreference::RP_* constants are deprecated in favor of the string constants
* Use ReadPreference::getModeString to compare with string constants
* Use $manager->selectServer() default primary
---
 src/Collection.php                            |  2 +-
 src/GridFS/CollectionWrapper.php              |  2 +-
 src/Operation/Watch.php                       |  2 +-
 src/functions.php                             |  6 ++--
 tests/ClientTest.php                          | 14 ++++-----
 tests/Collection/CollectionFunctionalTest.php |  8 ++---
 tests/Database/DatabaseFunctionalTest.php     | 30 +++++++++----------
 tests/DocumentationExamplesTest.php           |  8 ++---
 tests/FunctionalTestCase.php                  | 10 +++----
 tests/GridFS/BucketFunctionalTest.php         |  2 +-
 tests/Operation/AggregateFunctionalTest.php   |  2 +-
 .../Operation/FindAndModifyFunctionalTest.php |  3 +-
 tests/Operation/FindFunctionalTest.php        |  2 +-
 tests/Operation/WatchFunctionalTest.php       |  4 +--
 tests/SpecTests/Context.php                   |  4 +--
 tests/SpecTests/PrimaryStepDownSpecTest.php   |  8 ++---
 tests/SpecTests/TransactionsSpecTest.php      |  3 +-
 tests/TestCase.php                            |  6 ++--
 tests/UnifiedSpecTests/UnifiedTestRunner.php  |  5 ++--
 19 files changed, 59 insertions(+), 62 deletions(-)

diff --git a/src/Collection.php b/src/Collection.php
index f3d7e38ee..c6d0e30ec 100644
--- a/src/Collection.php
+++ b/src/Collection.php
@@ -968,7 +968,7 @@ public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce,
 
         // Check if the out option is inline because we will want to coerce a primary read preference if not
         if ($hasOutputCollection) {
-            $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY);
+            $options['readPreference'] = new ReadPreference(ReadPreference::PRIMARY);
         }
 
         $server = select_server($this->manager, $options);
diff --git a/src/GridFS/CollectionWrapper.php b/src/GridFS/CollectionWrapper.php
index 28218707c..4642028e3 100644
--- a/src/GridFS/CollectionWrapper.php
+++ b/src/GridFS/CollectionWrapper.php
@@ -359,7 +359,7 @@ private function indexKeysMatch(array $expectedKeys, array $actualKeys): bool
     private function isFilesCollectionEmpty(): bool
     {
         return null === $this->filesCollection->findOne([], [
-            'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
             'projection' => ['_id' => 1],
             'typeMap' => [],
         ]);
diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php
index 2e6bf00c0..5dde8d014 100644
--- a/src/Operation/Watch.php
+++ b/src/Operation/Watch.php
@@ -208,7 +208,7 @@ public function __construct(Manager $manager, ?string $databaseName, ?string $co
         }
 
         $options += [
-            'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
         ];
 
         if (array_key_exists('fullDocument', $options) && ! is_string($options['fullDocument'])) {
diff --git a/src/functions.php b/src/functions.php
index 8a5f8e880..498d2dba4 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -558,7 +558,7 @@ function select_server(Manager $manager, array $options): Server
     $readPreference = extract_read_preference_from_options($options);
     if (! $readPreference instanceof ReadPreference) {
         // TODO: PHPLIB-476: Read transaction read preference once PHPC-1439 is implemented
-        $readPreference = new ReadPreference(ReadPreference::RP_PRIMARY);
+        $readPreference = new ReadPreference(ReadPreference::PRIMARY);
     }
 
     return $manager->selectServer($readPreference);
@@ -578,7 +578,7 @@ function select_server_for_aggregate_write_stage(Manager $manager, array &$optio
 
     /* If there is either no read preference or a primary read preference, there
      * is no special server selection logic to apply. */
-    if ($readPreference === null || $readPreference->getMode() === ReadPreference::RP_PRIMARY) {
+    if ($readPreference === null || $readPreference->getModeString() === ReadPreference::PRIMARY) {
         return select_server($manager, $options);
     }
 
@@ -594,7 +594,7 @@ function select_server_for_aggregate_write_stage(Manager $manager, array &$optio
      * preference and repeat server selection if it previously failed or
      * selected a secondary. */
     if (! all_servers_support_write_stage_on_secondary($manager->getServers())) {
-        $options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY);
+        $options['readPreference'] = new ReadPreference(ReadPreference::PRIMARY);
 
         if ($server === null || $server->isSecondary()) {
             return select_server($manager, $options);
diff --git a/tests/ClientTest.php b/tests/ClientTest.php
index de9705415..04855d479 100644
--- a/tests/ClientTest.php
+++ b/tests/ClientTest.php
@@ -95,7 +95,7 @@ public function testSelectCollectionInheritsOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -106,7 +106,7 @@ public function testSelectCollectionPassesOptions(): void
     {
         $collectionOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -118,7 +118,7 @@ public function testSelectCollectionPassesOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -142,7 +142,7 @@ public function testSelectDatabaseInheritsOptions(): void
     {
         $uriOptions = [
             'readConcernLevel' => ReadConcern::LOCAL,
-            'readPreference' => 'secondaryPreferred',
+            'readPreference' => ReadPreference::SECONDARY_PREFERRED,
             'w' => WriteConcern::MAJORITY,
         ];
 
@@ -157,7 +157,7 @@ public function testSelectDatabaseInheritsOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -168,7 +168,7 @@ public function testSelectDatabasePassesOptions(): void
     {
         $databaseOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -180,7 +180,7 @@ public function testSelectDatabasePassesOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php
index 0310a0c2a..0b3505448 100644
--- a/tests/Collection/CollectionFunctionalTest.php
+++ b/tests/Collection/CollectionFunctionalTest.php
@@ -371,7 +371,7 @@ public function testWithOptionsInheritsOptions(): void
     {
         $collectionOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -386,7 +386,7 @@ public function testWithOptionsInheritsOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -397,7 +397,7 @@ public function testWithOptionsPassesOptions(): void
     {
         $collectionOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -408,7 +408,7 @@ public function testWithOptionsPassesOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
diff --git a/tests/Database/DatabaseFunctionalTest.php b/tests/Database/DatabaseFunctionalTest.php
index 1f5707911..d1f74025c 100644
--- a/tests/Database/DatabaseFunctionalTest.php
+++ b/tests/Database/DatabaseFunctionalTest.php
@@ -86,7 +86,7 @@ public function testCommand(): void
     {
         $command = ['ping' => 1];
         $options = [
-            'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
         ];
 
         $cursor = $this->database->command($command, $options);
@@ -105,7 +105,7 @@ public function testCommandDoesNotInheritReadPreference(): void
             $this->markTestSkipped('Test only applies to replica sets');
         }
 
-        $this->database = new Database($this->manager, $this->getDatabaseName(), ['readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY)]);
+        $this->database = new Database($this->manager, $this->getDatabaseName(), ['readPreference' => new ReadPreference(ReadPreference::SECONDARY)]);
 
         $command = ['ping' => 1];
 
@@ -119,7 +119,7 @@ public function testCommandAppliesTypeMapToCursor(): void
     {
         $command = ['ping' => 1];
         $options = [
-            'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
             'typeMap' => ['root' => 'array'],
         ];
 
@@ -286,7 +286,7 @@ public function testSelectCollectionInheritsOptions(): void
     {
         $databaseOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -301,7 +301,7 @@ public function testSelectCollectionInheritsOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -312,7 +312,7 @@ public function testSelectCollectionPassesOptions(): void
     {
         $collectionOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -323,7 +323,7 @@ public function testSelectCollectionPassesOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -334,7 +334,7 @@ public function testSelectGridFSBucketInheritsOptions(): void
     {
         $databaseOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
 
@@ -349,7 +349,7 @@ public function testSelectGridFSBucketInheritsOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
         $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW());
     }
@@ -360,7 +360,7 @@ public function testSelectGridFSBucketPassesOptions(): void
             'bucketName' => 'custom_fs',
             'chunkSizeBytes' => 8192,
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
 
@@ -374,7 +374,7 @@ public function testSelectGridFSBucketPassesOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
         $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW());
     }
@@ -383,7 +383,7 @@ public function testWithOptionsInheritsOptions(): void
     {
         $databaseOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -397,7 +397,7 @@ public function testWithOptionsInheritsOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
@@ -408,7 +408,7 @@ public function testWithOptionsPassesOptions(): void
     {
         $databaseOptions = [
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
             'typeMap' => ['root' => 'array'],
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
         ];
@@ -419,7 +419,7 @@ public function testWithOptionsPassesOptions(): void
         $this->assertInstanceOf(ReadConcern::class, $debug['readConcern']);
         $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
         $this->assertInstanceOf(ReadPreference::class, $debug['readPreference']);
-        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
+        $this->assertSame(ReadPreference::SECONDARY_PREFERRED, $debug['readPreference']->getModeString());
         $this->assertIsArray($debug['typeMap']);
         $this->assertSame(['root' => 'array'], $debug['typeMap']);
         $this->assertInstanceOf(WriteConcern::class, $debug['writeConcern']);
diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index 096edeea9..e0bffc1af 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -1411,7 +1411,7 @@ private function updateEmployeeInfo3(\MongoDB\Client $client, \MongoDB\Driver\Se
     {
         $session->startTransaction([
             'readConcern' => new \MongoDB\Driver\ReadConcern("snapshot"),
-            'readPrefernece' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_PRIMARY),
+            'readPrefernece' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::PRIMARY),
             'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY),
         ]);
 
@@ -1496,7 +1496,7 @@ public function testCausalConsistency(): void
              * mode, so using $manager->selectServer does not work here. To work
              * around this, we run a query on a secondary and rely on an
              * exception to let us know that no secondary is available. */
-            $items->countDocuments([], ['readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY)]);
+            $items->countDocuments([], ['readPreference' => new ReadPreference(ReadPreference::SECONDARY)]);
         } catch (Exception $e) {
             $this->markTestSkipped('Secondary is not available');
         }
@@ -1542,7 +1542,7 @@ public function testCausalConsistency(): void
         $items = $client->selectDatabase(
             'test',
             [
-                'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_SECONDARY),
+                'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::SECONDARY),
                 'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::MAJORITY),
                 'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
             ]
@@ -1823,7 +1823,7 @@ public function testWithTransactionExample(): void
         $transactionOptions = [
             'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL),
             'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
-            'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::RP_PRIMARY),
+            'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::PRIMARY),
         ];
 
         \MongoDB\with_transaction($session, $callback, $transactionOptions);
diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php
index 500bd5263..926010e5c 100644
--- a/tests/FunctionalTestCase.php
+++ b/tests/FunctionalTestCase.php
@@ -290,7 +290,7 @@ protected function getFeatureCompatibilityVersion(?ReadPreference $readPreferenc
         $cursor = $this->manager->executeCommand(
             'admin',
             new Command(['getParameter' => 1, 'featureCompatibilityVersion' => 1]),
-            $readPreference ?: new ReadPreference(ReadPreference::RP_PRIMARY)
+            $readPreference ?: new ReadPreference(ReadPreference::PRIMARY)
         );
 
         $cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
@@ -305,7 +305,7 @@ protected function getFeatureCompatibilityVersion(?ReadPreference $readPreferenc
 
     protected function getPrimaryServer()
     {
-        return $this->manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
+        return $this->manager->selectServer();
     }
 
     protected function getServerVersion(?ReadPreference $readPreference = null)
@@ -313,7 +313,7 @@ protected function getServerVersion(?ReadPreference $readPreference = null)
         $buildInfo = $this->manager->executeCommand(
             $this->getDatabaseName(),
             new Command(['buildInfo' => 1]),
-            $readPreference ?: new ReadPreference(ReadPreference::RP_PRIMARY)
+            $readPreference ?: new ReadPreference(ReadPreference::PRIMARY)
         )->toArray()[0];
 
         if (isset($buildInfo->version) && is_string($buildInfo->version)) {
@@ -328,7 +328,7 @@ protected function getServerStorageEngine(?ReadPreference $readPreference = null
         $cursor = $this->manager->executeCommand(
             $this->getDatabaseName(),
             new Command(['serverStatus' => 1]),
-            $readPreference ?: new ReadPreference('primary')
+            $readPreference ?: new ReadPreference(ReadPreference::PRIMARY)
         );
 
         $result = current($cursor->toArray());
@@ -611,7 +611,7 @@ private static function getUriWithoutMultipleMongoses(): string
         }
 
         $manager = static::createTestManager($uri);
-        if ($manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY))->getType() !== Server::TYPE_MONGOS) {
+        if ($manager->selectServer()->getType() !== Server::TYPE_MONGOS) {
             return $uri;
         }
 
diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php
index dbdfe2017..395feaa95 100644
--- a/tests/GridFS/BucketFunctionalTest.php
+++ b/tests/GridFS/BucketFunctionalTest.php
@@ -51,7 +51,7 @@ public function testValidConstructorOptions(): void
             'bucketName' => 'test',
             'chunkSizeBytes' => 8192,
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
-            'readPreference' => new ReadPreference(ReadPreference::RP_PRIMARY),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY, 1000),
         ]);
     }
diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php
index ac0a2e767..0ac9b000a 100644
--- a/tests/Operation/AggregateFunctionalTest.php
+++ b/tests/Operation/AggregateFunctionalTest.php
@@ -315,7 +315,7 @@ public function testReadPreferenceWithinTransaction(): void
 
             $pipeline = [['$match' => ['_id' => ['$lt' => 3]]]];
             $options = [
-                'readPreference' => new ReadPreference('primary'),
+                'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
                 'session' => $session,
             ];
 
diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php
index 4680ec84c..86d2747f9 100644
--- a/tests/Operation/FindAndModifyFunctionalTest.php
+++ b/tests/Operation/FindAndModifyFunctionalTest.php
@@ -6,7 +6,6 @@
 use MongoDB\BSON\PackedArray;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\Exception\CommandException;
-use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\UnsupportedException;
 use MongoDB\Model\BSONArray;
@@ -115,7 +114,7 @@ public function provideUpdatePipelines(): array
     public function testManagerReadConcernIsOmitted(): void
     {
         $manager = static::createTestManager(null, ['readConcernLevel' => 'majority']);
-        $server = $manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
+        $server = $manager->selectServer();
 
         (new CommandObserver())->observe(
             function () use ($server): void {
diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php
index 42f11ba7e..11eb5246b 100644
--- a/tests/Operation/FindFunctionalTest.php
+++ b/tests/Operation/FindFunctionalTest.php
@@ -288,7 +288,7 @@ public function testReadPreferenceWithinTransaction(): void
 
             $filter = ['_id' => ['$lt' => 3]];
             $options = [
-                'readPreference' => new ReadPreference('primary'),
+                'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
                 'session' => $session,
             ];
 
diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php
index aefadcb56..dc1e12c8b 100644
--- a/tests/Operation/WatchFunctionalTest.php
+++ b/tests/Operation/WatchFunctionalTest.php
@@ -165,7 +165,7 @@ public function testNextResumesAfterConnectionException(): void
          * a socket timeout that is less than the change stream's maxAwaitTimeMS
          * option. */
         $manager = static::createTestManager(null, ['socketTimeoutMS' => 50]);
-        $primaryServer = $manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
+        $primaryServer = $manager->selectServer();
 
         $operation = new Watch($manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
         $changeStream = $operation->execute($primaryServer);
@@ -1321,7 +1321,7 @@ public function testOriginalReadPreferenceIsPreservedOnResume(): void
             $this->markTestSkipped('Test does not apply to sharded clusters');
         }
 
-        $readPreference = new ReadPreference('secondary');
+        $readPreference = new ReadPreference(ReadPreference::SECONDARY);
         $options = ['readPreference' => $readPreference] + $this->defaultOptions;
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $options);
 
diff --git a/tests/SpecTests/Context.php b/tests/SpecTests/Context.php
index 226f94286..326061639 100644
--- a/tests/SpecTests/Context.php
+++ b/tests/SpecTests/Context.php
@@ -163,7 +163,7 @@ public static function fromCrud(stdClass $test, $databaseName, $collectionName)
 
         $o->outcomeReadOptions = [
             'readConcern' => new ReadConcern('local'),
-            'readPreference' => new ReadPreference('primary'),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
         ];
 
         $o->client = self::createTestClient(null, $clientOptions);
@@ -224,7 +224,7 @@ public static function fromTransactions(stdClass $test, $databaseName, $collecti
 
         $o->outcomeReadOptions = [
             'readConcern' => new ReadConcern('local'),
-            'readPreference' => new ReadPreference('primary'),
+            'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
         ];
 
         $clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : [];
diff --git a/tests/SpecTests/PrimaryStepDownSpecTest.php b/tests/SpecTests/PrimaryStepDownSpecTest.php
index 1d83faaba..db028d7d9 100644
--- a/tests/SpecTests/PrimaryStepDownSpecTest.php
+++ b/tests/SpecTests/PrimaryStepDownSpecTest.php
@@ -208,7 +208,7 @@ public function testGetMoreIteration(): void
         $totalConnectionsCreated = $this->getTotalConnectionsCreated();
 
         // Send a {replSetStepDown: 5, force: true} command to the current primary and verify that the command succeeded
-        $primary = $this->client->getManager()->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
+        $primary = $this->client->getManager()->selectServer();
 
         $success = false;
         $attempts = 0;
@@ -267,12 +267,12 @@ private function dropAndRecreateCollection(): void
 
     private function getTotalConnectionsCreated(?Server $server = null)
     {
-        $server = $server ?: $this->client->getManager()->selectServer(new ReadPreference('primary'));
+        $server = $server ?: $this->client->getManager()->selectServer();
 
         $cursor = $server->executeCommand(
             $this->getDatabaseName(),
             new Command(['serverStatus' => 1]),
-            new ReadPreference(ReadPreference::RP_PRIMARY)
+            new ReadPreference(ReadPreference::PRIMARY)
         );
 
         $cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
@@ -292,7 +292,7 @@ private function waitForPrimaryReelection(): void
 
             return;
         } catch (DriverException $e) {
-            $this->client->getManager()->selectServer(new ReadPreference('primary'));
+            $this->client->getManager()->selectServer();
 
             return;
         }
diff --git a/tests/SpecTests/TransactionsSpecTest.php b/tests/SpecTests/TransactionsSpecTest.php
index 768dd0b40..e88fee203 100644
--- a/tests/SpecTests/TransactionsSpecTest.php
+++ b/tests/SpecTests/TransactionsSpecTest.php
@@ -6,7 +6,6 @@
 use MongoDB\BSON\Timestamp;
 use MongoDB\Driver\Command;
 use MongoDB\Driver\Exception\ServerException;
-use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\Server;
 use stdClass;
 
@@ -320,7 +319,7 @@ private static function killAllSessions(): void
         }
 
         $manager = static::createTestManager();
-        $primary = $manager->selectServer(new ReadPreference('primary'));
+        $primary = $manager->selectServer();
 
         $servers = $primary->getType() === Server::TYPE_MONGOS
             ? $manager->getServers()
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 8e87a5edb..91e1244de 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -210,7 +210,7 @@ protected function getInvalidIntegerValues(bool $includeNull = false): array
      */
     protected function getInvalidReadConcernValues(bool $includeNull = false): array
     {
-        return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []);
+        return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadPreference(ReadPreference::PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []);
     }
 
     /**
@@ -226,7 +226,7 @@ protected function getInvalidReadPreferenceValues(bool $includeNull = false): ar
      */
     protected function getInvalidSessionValues(bool $includeNull = false): array
     {
-        return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::RP_PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []);
+        return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::PRIMARY), new WriteConcern(1)], $includeNull ? [null] : []);
     }
 
     /**
@@ -242,7 +242,7 @@ protected function getInvalidStringValues(bool $includeNull = false): array
      */
     protected function getInvalidWriteConcernValues(bool $includeNull = false): array
     {
-        return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::RP_PRIMARY)], $includeNull ? [null] : []);
+        return array_merge([123, 3.14, 'foo', true, [], new stdClass(), new ReadConcern(), new ReadPreference(ReadPreference::PRIMARY)], $includeNull ? [null] : []);
     }
 
     /**
diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php
index e3df84cff..946ff32b2 100644
--- a/tests/UnifiedSpecTests/UnifiedTestRunner.php
+++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php
@@ -4,7 +4,6 @@
 
 use MongoDB\Collection;
 use MongoDB\Driver\Exception\ServerException;
-use MongoDB\Driver\ReadPreference;
 use MongoDB\Driver\Server;
 use MongoDB\Model\BSONArray;
 use MongoDB\Operation\DatabaseCommand;
@@ -279,7 +278,7 @@ private function getPrimaryServer(): Server
     {
         $manager = $this->internalClient->getManager();
 
-        return $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY));
+        return $manager->selectServer();
     }
 
     private function getServerVersion(): string
@@ -438,7 +437,7 @@ private function killAllSessions(): void
         }
 
         $manager = $this->internalClient->getManager();
-        $primary = $manager->selectServer(new ReadPreference(ReadPreference::PRIMARY));
+        $primary = $manager->selectServer();
         $servers = $primary->getType() === Server::TYPE_MONGOS ? $manager->getServers() : [$primary];
 
         foreach ($servers as $server) {

From b3b6b0b338bde39029050c1e34188288db44bb8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 1 Jun 2023 17:27:55 +0200
Subject: [PATCH 298/321] PHPLIB-816: Cleanup collections created when tests
 are successful (#1075)

- Update FunctionalTestCase::createCollection and FunctionalTestCase::dropCollection to accept a different database and collection name.
- Remove automatically the collections created or dropped using this helper methods.
- Use this methods when possible.
---
 tests/Collection/CollectionFunctionalTest.php |  10 +-
 tests/Collection/CrudSpecFunctionalTest.php   |   3 +-
 tests/Collection/FunctionalTestCase.php       |  13 +--
 tests/DocumentationExamplesTest.php           | 103 +++++++-----------
 tests/FunctionalTestCase.php                  |  67 +++++++++---
 tests/Model/ChangeStreamIteratorTest.php      |  11 +-
 tests/Model/IndexInfoFunctionalTest.php       |  12 +-
 tests/Operation/AggregateFunctionalTest.php   |   2 +-
 tests/Operation/ExplainFunctionalTest.php     |   4 +-
 tests/Operation/FindFunctionalTest.php        |   6 +-
 tests/Operation/FunctionalTestCase.php        |  11 +-
 tests/Operation/ListIndexesFunctionalTest.php |   7 +-
 tests/Operation/MapReduceFunctionalTest.php   |  14 +--
 .../ModifyCollectionFunctionalTest.php        |   2 +-
 .../RenameCollectionFunctionalTest.php        |  15 +--
 tests/Operation/WatchFunctionalTest.php       |   4 +-
 16 files changed, 116 insertions(+), 168 deletions(-)

diff --git a/tests/Collection/CollectionFunctionalTest.php b/tests/Collection/CollectionFunctionalTest.php
index 0b3505448..24c5903b9 100644
--- a/tests/Collection/CollectionFunctionalTest.php
+++ b/tests/Collection/CollectionFunctionalTest.php
@@ -114,7 +114,7 @@ public function testAggregateWithinTransaction(): void
         $this->skipIfTransactionsAreNotSupported();
 
         // Collection must be created before the transaction starts
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
@@ -294,7 +294,7 @@ public function testFindWithinTransaction(): void
         $this->skipIfTransactionsAreNotSupported();
 
         // Collection must be created before the transaction starts
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
@@ -727,7 +727,7 @@ public function testMethodDoesNotInheritReadWriteConcernInTranasaction(Closure $
     {
         $this->skipIfTransactionsAreNotSupported();
 
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
@@ -753,7 +753,7 @@ public function testMethodInTransactionWithWriteConcernOption($method): void
     {
         $this->skipIfTransactionsAreNotSupported();
 
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
@@ -773,7 +773,7 @@ public function testMethodInTransactionWithReadConcernOption($method): void
     {
         $this->skipIfTransactionsAreNotSupported();
 
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php
index 6a81da1a6..620e35298 100644
--- a/tests/Collection/CrudSpecFunctionalTest.php
+++ b/tests/Collection/CrudSpecFunctionalTest.php
@@ -48,8 +48,7 @@ public function setUp(): void
     {
         parent::setUp();
 
-        $this->expectedCollection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName() . '.expected');
-        $this->expectedCollection->drop();
+        $this->expectedCollection = $this->dropCollection($this->getDatabaseName(), $this->getCollectionName() . '.expected');
     }
 
     /** @dataProvider provideSpecificationTests */
diff --git a/tests/Collection/FunctionalTestCase.php b/tests/Collection/FunctionalTestCase.php
index f0855267f..d299d18fa 100644
--- a/tests/Collection/FunctionalTestCase.php
+++ b/tests/Collection/FunctionalTestCase.php
@@ -17,17 +17,6 @@ public function setUp(): void
     {
         parent::setUp();
 
-        $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
-
-        $this->dropCollection();
-    }
-
-    public function tearDown(): void
-    {
-        if (! $this->hasFailed()) {
-            $this->dropCollection();
-        }
-
-        parent::tearDown();
+        $this->collection = $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 }
diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index e0bffc1af..a5b368809 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -11,7 +11,6 @@
 use MongoDB\Driver\Exception\CommandException;
 use MongoDB\Driver\Exception\Exception;
 use MongoDB\Driver\ReadPreference;
-use MongoDB\Driver\WriteConcern;
 use MongoDB\Tests\SpecTests\ClientSideEncryptionSpecTest;
 
 use function base64_decode;
@@ -32,24 +31,9 @@
  */
 class DocumentationExamplesTest extends FunctionalTestCase
 {
-    public function setUp(): void
-    {
-        parent::setUp();
-
-        $this->dropCollection();
-    }
-
-    public function tearDown(): void
-    {
-        if (! $this->hasFailed()) {
-            $this->dropCollection();
-        }
-
-        parent::tearDown();
-    }
-
     public function testExample_1_2(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 1
@@ -74,6 +58,7 @@ public function testExample_1_2(): void
 
     public function testExample_3(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 3
@@ -109,6 +94,7 @@ public function testExample_3(): void
 
     public function testExample_6_13(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 6
@@ -213,6 +199,7 @@ public function testExample_6_13(): void
 
     public function testExample_14_19(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 14
@@ -294,6 +281,7 @@ public function testExample_14_19(): void
 
     public function testExample_20_28(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 20
@@ -401,6 +389,7 @@ public function testExample_20_28(): void
 
     public function testExample_29_37(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 29
@@ -500,6 +489,7 @@ public function testExample_29_37(): void
 
     public function testExample_38_41(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 38
@@ -537,6 +527,7 @@ public function testExample_38_41(): void
 
     public function testExample_42_50(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 42
@@ -742,6 +733,7 @@ public function testExample_42_50(): void
 
     public function testExample_51_54(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 51
@@ -883,6 +875,7 @@ public function testExample_51_54(): void
 
     public function testExample_55_58(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Example 55
@@ -960,9 +953,8 @@ public function testChangeStreamExample_1_4(): void
             $this->markTestSkipped('Test does not apply on sharded clusters: need more than a single getMore call on the change stream.');
         }
 
+        $this->createCollection($this->getDatabaseName(), 'inventory');
         $db = new Database($this->manager, $this->getDatabaseName());
-        $db->dropCollection('inventory');
-        $db->createCollection('inventory');
 
         // Start Changestream Example 1
         $changeStream = $db->inventory->watch();
@@ -1060,6 +1052,7 @@ public function testChangeStreamExample_1_4(): void
 
     public function testAggregation_example_1(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'sales');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Aggregation Example 1
@@ -1074,6 +1067,7 @@ public function testAggregation_example_1(): void
 
     public function testAggregation_example_2(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'sales');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Aggregation Example 2
@@ -1102,6 +1096,7 @@ public function testAggregation_example_2(): void
 
     public function testAggregation_example_3(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'sales');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Aggregation Example 3
@@ -1140,6 +1135,7 @@ public function testAggregation_example_3(): void
 
     public function testAggregation_example_4(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'air_airlines');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // phpcs:disable Squiz.NamingConventions.ValidVariableName.MemberNotCamelCaps
@@ -1192,6 +1188,7 @@ public function testRunCommand_example_1(): void
 
     public function testIndex_example_1(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'records');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Index Example 1
@@ -1203,6 +1200,7 @@ public function testIndex_example_1(): void
 
     public function testIndex_example_2(): void
     {
+        $this->dropCollection($this->getDatabaseName(), 'restaurants');
         $db = new Database($this->manager, $this->getDatabaseName());
 
         // Start Index Example 2
@@ -1277,13 +1275,9 @@ public function testTransactions_intro_example_1(): void
 
         $client = static::createTestClient();
 
-        /* The WC is required: https://mongodb.com/docs/manual/core/transactions/#transactions-and-locks */
-        $client->hr->dropCollection('employees', ['writeConcern' => new WriteConcern('majority')]);
-        $client->reporting->dropCollection('events', ['writeConcern' => new WriteConcern('majority')]);
-
         /* Collections need to be created before a transaction starts */
-        $client->hr->createCollection('employees', ['writeConcern' => new WriteConcern('majority')]);
-        $client->reporting->createCollection('events', ['writeConcern' => new WriteConcern('majority')]);
+        $this->createCollection('hr', 'employees');
+        $this->createCollection('reporting', 'events');
 
         $session = $client->startSession();
 
@@ -1457,13 +1451,9 @@ public function testTransactions_retry_example_3(): void
 
         $client = static::createTestClient();
 
-        /* The WC is required: https://mongodb.com/docs/manual/core/transactions/#transactions-and-locks */
-        $client->hr->dropCollection('employees', ['writeConcern' => new WriteConcern('majority')]);
-        $client->reporting->dropCollection('events', ['writeConcern' => new WriteConcern('majority')]);
-
         /* Collections need to be created before a transaction starts */
-        $client->hr->createCollection('employees', ['writeConcern' => new WriteConcern('majority')]);
-        $client->reporting->createCollection('events', ['writeConcern' => new WriteConcern('majority')]);
+        $this->createCollection('hr', 'employees');
+        $this->createCollection('reporting', 'events');
 
         ob_start();
         try {
@@ -1481,12 +1471,7 @@ public function testCausalConsistency(): void
 
         // Prep
         $client = static::createTestClient();
-        $items = $client->selectDatabase(
-            'test',
-            ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]
-        )->items;
-
-        $items->drop();
+        $items = $this->createCollection('test', 'items');
         $items->insertOne(
             ['sku' => '111', 'name' => 'Peanuts', 'start' => new UTCDateTime()]
         );
@@ -1572,17 +1557,13 @@ public function testSnapshotQueries(): void
             $this->markTestSkipped('Snapshot read concern is only supported with replicasets');
         }
 
-        $client = static::createTestClient();
-
-        $catsCollection = $client->selectCollection('pets', 'cats');
-        $catsCollection->drop();
+        $catsCollection = $this->dropCollection('pets', 'cats');
         $catsCollection->insertMany([
             ['name' => 'Whiskers', 'color' => 'white', 'adoptable' => true],
             ['name' => 'Garfield', 'color' => 'orange', 'adoptable' => false],
         ]);
 
-        $dogsCollection = $client->selectCollection('pets', 'dogs');
-        $dogsCollection->drop();
+        $dogsCollection = $this->dropCollection('pets', 'dogs');
         $dogsCollection->insertMany([
             ['name' => 'Toto', 'color' => 'black',  'adoptable' => true],
             ['name' => 'Milo', 'color' => 'black', 'adoptable' => false],
@@ -1597,6 +1578,8 @@ public function testSnapshotQueries(): void
             $this->waitForSnapshot('pets', 'dogs');
         }
 
+        $client = static::createTestClient();
+
         ob_start();
 
         // Start Snapshot Query Example 1
@@ -1628,11 +1611,7 @@ public function testSnapshotQueries(): void
 
         $this->assertSame(3, $adoptablePetsCount);
 
-        $catsCollection->drop();
-        $dogsCollection->drop();
-
-        $salesCollection = $client->selectCollection('retail', 'sales');
-        $salesCollection->drop();
+        $salesCollection = $this->dropCollection('retail', 'sales');
         $salesCollection->insertMany([
             ['shoeType' => 'boot', 'price' => 30, 'saleDate' => new UTCDateTime()],
         ]);
@@ -1671,8 +1650,6 @@ public function testSnapshotQueries(): void
         // End Snapshot Query Example 2
 
         $this->assertSame(1, $totalDailySales);
-
-        $salesCollection->drop();
     }
 
     /** @doesNotPerformAssertions */
@@ -1713,13 +1690,13 @@ public function testVersionedApiMigration(): void
             $this->markTestSkipped('The count command was added to API version 1 (SERVER-63850)');
         }
 
+        $this->dropCollection($this->getDatabaseName(), 'sales');
         $uriString = static::getUri(true);
 
         // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
         $serverApi = new \MongoDB\Driver\ServerApi('1', true);
         $client = new \MongoDB\Client($uriString, [], ['serverApi' => $serverApi]);
         $db = $client->selectDatabase($this->getDatabaseName());
-        $db->dropCollection('sales');
 
         // Start Versioned API Example 5
         $strtoutc = function (string $datetime) {
@@ -1773,6 +1750,8 @@ public function testWithTransactionExample(): void
         $this->skipIfTransactionsAreNotSupported();
 
         $uriString = static::getUri(true);
+        $this->dropCollection('mydb1', 'foo');
+        $this->dropCollection('mydb2', 'bar');
 
         // phpcs:disable SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
         // Start Transactions withTxn API Example 1
@@ -1857,13 +1836,13 @@ public function testQueryableEncryption(): void
         $databaseName = $this->getDatabaseName();
         $namespace = $this->getNamespace();
 
-        /* Create a client without auto encryption. Drop existing data in both
-         * the keyvault and database under test. The latter is necessary since
-         * setUp() only drops the collection under test, which will leave behind
-         * internal collections for queryable encryption. */
+        /* Create a client without auto encryption. Drop existing data in both the
+         * keyvault and the collection under test, the "encryptedFields" option
+         * is necessary to clean up any internal collections for queryable
+         * encryption, assuming they use their default names */
         $client = static::createTestClient();
-        $client->selectDatabase('keyvault')->drop(['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
-        $client->selectDatabase($databaseName)->drop(['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]);
+        $this->dropCollection('keyvault', 'datakeys');
+        $this->dropCollection($databaseName, $collectionName, ['encryptedFields' => []]);
 
         /* Although ClientEncryption can be constructed directly, the library
          * provides a helper to do so. With this method, the keyVaultClient will
@@ -1937,14 +1916,6 @@ public function testQueryableEncryption(): void
         $this->assertInstanceOf(Binary::class, $result['encryptedUnindexed']);
     }
 
-    /**
-     * Return the test collection name.
-     */
-    protected function getCollectionName(): string
-    {
-        return 'inventory';
-    }
-
     private function assertCursorCount($count, Cursor $cursor): void
     {
         $this->assertCount($count, $cursor->toArray());
@@ -1952,7 +1923,7 @@ private function assertCursorCount($count, Cursor $cursor): void
 
     private function assertInventoryCount($count): void
     {
-        $this->assertCollectionCount($this->getDatabaseName() . '.' . $this->getCollectionName(), $count);
+        $this->assertCollectionCount($this->getDatabaseName() . '.inventory', $count);
     }
 
     private function waitForSnapshot(string $databaseName, string $collectionName): void
diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php
index 926010e5c..0e5e7de46 100644
--- a/tests/FunctionalTestCase.php
+++ b/tests/FunctionalTestCase.php
@@ -5,6 +5,7 @@
 use InvalidArgumentException;
 use MongoDB\BSON\ObjectId;
 use MongoDB\Client;
+use MongoDB\Collection;
 use MongoDB\Driver\Command;
 use MongoDB\Driver\Exception\CommandException;
 use MongoDB\Driver\Manager;
@@ -15,11 +16,11 @@
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Operation\CreateCollection;
 use MongoDB\Operation\DatabaseCommand;
-use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\ListCollections;
 use stdClass;
 use UnexpectedValueException;
 
+use function array_intersect_key;
 use function call_user_func;
 use function count;
 use function current;
@@ -54,6 +55,9 @@ abstract class FunctionalTestCase extends TestCase
     /** @var array */
     private $configuredFailPoints = [];
 
+    /** @var array{int,{Collection,array}} */
+    private $collectionsToCleanup = [];
+
     public function setUp(): void
     {
         parent::setUp();
@@ -64,6 +68,10 @@ public function setUp(): void
 
     public function tearDown(): void
     {
+        if (! $this->hasFailed()) {
+            $this->cleanupCollections();
+        }
+
         $this->disableFailPoints();
 
         parent::tearDown();
@@ -252,33 +260,62 @@ public static function getModuleInfo(string $row): ?string
     }
 
     /**
-     * Creates the test collection with the specified options.
+     * Creates the test collection with the specified options and ensures it is
+     * dropped again during tearDown(). If the collection already exists, it
+     * is dropped and recreated.
      *
-     * If the "writeConcern" option is not specified but is supported by the
-     * server, a majority write concern will be used. This is helpful for tests
-     * using transactions or secondary reads.
+     * A majority write concern is applied by default to ensure that the
+     * transaction can acquire the required locks.
+     * See: https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations
+     *
+     * @param array $options CreateCollection options
      */
-    protected function createCollection(array $options = []): void
+    protected function createCollection(string $databaseName, string $collectionName, array $options = []): Collection
     {
-        $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)];
+        // See: https://jira.mongodb.org/browse/PHPLIB-1145
+        if (isset($options['encryptedFields'])) {
+            throw new InvalidArgumentException('The "encryptedFields" option is not supported by createCollection(). Time to refactor!');
+        }
+
+        // Pass only relevant options to drop the collection in case it already exists
+        $dropOptions = array_intersect_key($options, ['writeConcern' => 1, 'encryptedFields' => 1]);
+        $collection = $this->dropCollection($databaseName, $collectionName, $dropOptions);
 
-        $operation = new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), $options);
+        $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)];
+        $operation = new CreateCollection($databaseName, $collectionName, $options);
         $operation->execute($this->getPrimaryServer());
+
+        return $collection;
     }
 
     /**
-     * Drops the test collection with the specified options.
+     * Drops the test collection and ensures it is dropped again during tearDown().
      *
-     * If the "writeConcern" option is not specified but is supported by the
-     * server, a majority write concern will be used. This is helpful for tests
-     * using transactions or secondary reads.
+     * A majority write concern is applied by default to ensure that the
+     * transaction can acquire the required locks.
+     * See: https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations
+     *
+     * @param array $options Collection::dropCollection() options
      */
-    protected function dropCollection(array $options = []): void
+    protected function dropCollection(string $databaseName, string $collectionName, array $options = []): Collection
     {
+        $collection = new Collection($this->manager, $databaseName, $collectionName);
+        $this->collectionsToCleanup[] = [$collection, $options];
+
         $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)];
+        $collection->drop($options);
 
-        $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName(), $options);
-        $operation->execute($this->getPrimaryServer());
+        return $collection;
+    }
+
+    private function cleanupCollections(): void
+    {
+        foreach ($this->collectionsToCleanup as [$collection, $options]) {
+            $options += ['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)];
+            $collection->drop($options);
+        }
+
+        $this->collectionsToCleanup = [];
     }
 
     protected function getFeatureCompatibilityVersion(?ReadPreference $readPreference = null)
diff --git a/tests/Model/ChangeStreamIteratorTest.php b/tests/Model/ChangeStreamIteratorTest.php
index f596755fb..c0001d6d7 100644
--- a/tests/Model/ChangeStreamIteratorTest.php
+++ b/tests/Model/ChangeStreamIteratorTest.php
@@ -11,8 +11,6 @@
 use MongoDB\Driver\Exception\LogicException;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Model\ChangeStreamIterator;
-use MongoDB\Operation\CreateCollection;
-use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\Find;
 use MongoDB\Tests\CommandObserver;
 use MongoDB\Tests\FunctionalTestCase;
@@ -30,13 +28,8 @@ public function setUp(): void
     {
         parent::setUp();
 
-        $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName());
-        $operation->execute($this->getPrimaryServer());
-
-        $operation = new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['capped' => true, 'size' => 8192]);
-        $operation->execute($this->getPrimaryServer());
-
-        $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
+        // Drop and re-create the collection
+        $this->collection = $this->createCollection($this->getDatabaseName(), $this->getCollectionName(), ['capped' => true, 'size' => 8192]);
     }
 
     /** @dataProvider provideInvalidIntegerValues */
diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php
index a2b5868d7..f7e19e513 100644
--- a/tests/Model/IndexInfoFunctionalTest.php
+++ b/tests/Model/IndexInfoFunctionalTest.php
@@ -14,17 +14,7 @@ public function setUp(): void
     {
         parent::setUp();
 
-        $this->collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName());
-        $this->collection->drop();
-    }
-
-    public function tearDown(): void
-    {
-        if (! $this->hasFailed()) {
-            $this->collection->drop();
-        }
-
-        parent::tearDown();
+        $this->collection = $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 
     public function testIs2dSphere(): void
diff --git a/tests/Operation/AggregateFunctionalTest.php b/tests/Operation/AggregateFunctionalTest.php
index 0ac9b000a..4e7582975 100644
--- a/tests/Operation/AggregateFunctionalTest.php
+++ b/tests/Operation/AggregateFunctionalTest.php
@@ -305,7 +305,7 @@ public function testReadPreferenceWithinTransaction(): void
         $this->skipIfTransactionsAreNotSupported();
 
         // Collection must be created before the transaction starts
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php
index 5388f6752..264289013 100644
--- a/tests/Operation/ExplainFunctionalTest.php
+++ b/tests/Operation/ExplainFunctionalTest.php
@@ -5,7 +5,6 @@
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Operation\Aggregate;
 use MongoDB\Operation\Count;
-use MongoDB\Operation\CreateCollection;
 use MongoDB\Operation\Delete;
 use MongoDB\Operation\DeleteMany;
 use MongoDB\Operation\DeleteOne;
@@ -137,8 +136,7 @@ public function testFindMaxAwait(): void
             'size' => 1048576,
         ];
 
-        $operation = new CreateCollection($databaseName, $cappedCollectionName, $cappedCollectionOptions);
-        $operation->execute($this->getPrimaryServer());
+        $this->createCollection($databaseName, $cappedCollectionName, $cappedCollectionOptions);
 
         $this->createFixtures(2);
 
diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php
index 11eb5246b..a4238e0e5 100644
--- a/tests/Operation/FindFunctionalTest.php
+++ b/tests/Operation/FindFunctionalTest.php
@@ -6,7 +6,6 @@
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\ReadPreference;
 use MongoDB\Model\BSONDocument;
-use MongoDB\Operation\CreateCollection;
 use MongoDB\Operation\CreateIndexes;
 use MongoDB\Operation\Find;
 use MongoDB\Tests\CommandObserver;
@@ -227,8 +226,7 @@ public function testMaxAwaitTimeMS(): void
             'size' => 1048576,
         ];
 
-        $operation = new CreateCollection($databaseName, $cappedCollectionName, $cappedCollectionOptions);
-        $operation->execute($this->getPrimaryServer());
+        $this->createCollection($databaseName, $cappedCollectionName, $cappedCollectionOptions);
 
         // Insert documents into the capped collection.
         $bulkWrite = new BulkWrite(['ordered' => true]);
@@ -278,7 +276,7 @@ public function testReadPreferenceWithinTransaction(): void
         $this->skipIfTransactionsAreNotSupported();
 
         // Collection must be created before the transaction starts
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $session = $this->manager->startSession();
         $session->startTransaction();
diff --git a/tests/Operation/FunctionalTestCase.php b/tests/Operation/FunctionalTestCase.php
index df1eebdda..3da36fd71 100644
--- a/tests/Operation/FunctionalTestCase.php
+++ b/tests/Operation/FunctionalTestCase.php
@@ -15,16 +15,7 @@ public function setUp(): void
     {
         parent::setUp();
 
-        $this->dropCollection();
-    }
-
-    public function tearDown(): void
-    {
-        if (! $this->hasFailed()) {
-            $this->dropCollection();
-        }
-
-        parent::tearDown();
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 
     protected function createDefaultReadConcern()
diff --git a/tests/Operation/ListIndexesFunctionalTest.php b/tests/Operation/ListIndexesFunctionalTest.php
index d2d03bf48..98aef09f2 100644
--- a/tests/Operation/ListIndexesFunctionalTest.php
+++ b/tests/Operation/ListIndexesFunctionalTest.php
@@ -4,7 +4,6 @@
 
 use MongoDB\Model\IndexInfo;
 use MongoDB\Model\IndexInfoIterator;
-use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\InsertOne;
 use MongoDB\Operation\ListIndexes;
 use MongoDB\Tests\CommandObserver;
@@ -13,8 +12,7 @@ class ListIndexesFunctionalTest extends FunctionalTestCase
 {
     public function testListIndexesForNewlyCreatedCollection(): void
     {
-        $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName());
-        $operation->execute($this->getPrimaryServer());
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $insertOne = new InsertOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1]);
         $writeResult = $insertOne->execute($this->getPrimaryServer());
@@ -36,8 +34,7 @@ public function testListIndexesForNewlyCreatedCollection(): void
 
     public function testListIndexesForNonexistentCollection(): void
     {
-        $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName());
-        $operation->execute($this->getPrimaryServer());
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $operation = new ListIndexes($this->getDatabaseName(), $this->getCollectionName());
         $indexes = $operation->execute($this->getPrimaryServer());
diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php
index c58e42138..bdb3ffc7a 100644
--- a/tests/Operation/MapReduceFunctionalTest.php
+++ b/tests/Operation/MapReduceFunctionalTest.php
@@ -5,7 +5,6 @@
 use MongoDB\BSON\Javascript;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\MapReduceResult;
-use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\Find;
 use MongoDB\Operation\MapReduce;
 use MongoDB\Tests\CommandObserver;
@@ -26,7 +25,7 @@ class MapReduceFunctionalTest extends FunctionalTestCase
     public function testDefaultReadConcernIsOmitted(): void
     {
         // Collection must exist for mapReduce command
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         (new CommandObserver())->observe(
             function (): void {
@@ -50,7 +49,8 @@ function (array $event): void {
     public function testDefaultWriteConcernIsOmitted(): void
     {
         // Collection must exist for mapReduce command
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName() . '.output');
 
         (new CommandObserver())->observe(
             function (): void {
@@ -69,9 +69,6 @@ function (array $event): void {
                 $this->assertObjectNotHasAttribute('writeConcern', $event['started']->getCommand());
             }
         );
-
-        $operation = new DropCollection($this->getDatabaseName(), $this->getCollectionName() . '.output');
-        $operation->execute($this->getPrimaryServer());
     }
 
     public function testFinalize(): void
@@ -273,6 +270,7 @@ public function testTypeMapOptionWithOutputCollection(?array $typeMap, array $ex
         $map = new Javascript('function() { emit(this.x, this.y); }');
         $reduce = new Javascript('function(key, values) { return Array.sum(values); }');
         $out = $this->getCollectionName() . '.output';
+        $this->dropCollection($this->getDatabaseName(), $out);
 
         $operation = new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out, ['typeMap' => $typeMap]);
         $results = iterator_to_array($operation->execute($this->getPrimaryServer()));
@@ -283,9 +281,6 @@ public function testTypeMapOptionWithOutputCollection(?array $typeMap, array $ex
         $cursor = $operation->execute($this->getPrimaryServer());
 
         $this->assertEquals($this->sortResults($expectedDocuments), $this->sortResults(iterator_to_array($cursor)));
-
-        $operation = new DropCollection($this->getDatabaseName(), $out);
-        $operation->execute($this->getPrimaryServer());
     }
 
     /**
@@ -293,6 +288,7 @@ public function testTypeMapOptionWithOutputCollection(?array $typeMap, array $ex
      */
     private function createFixtures(int $n): void
     {
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
         $bulkWrite = new BulkWrite(['ordered' => true]);
 
         for ($i = 1; $i <= $n; $i++) {
diff --git a/tests/Operation/ModifyCollectionFunctionalTest.php b/tests/Operation/ModifyCollectionFunctionalTest.php
index 567bcdef7..5e971a0c8 100644
--- a/tests/Operation/ModifyCollectionFunctionalTest.php
+++ b/tests/Operation/ModifyCollectionFunctionalTest.php
@@ -18,7 +18,7 @@ public function testCollMod(): void
             $this->markTestSkipped('Sharded clusters may report result inconsistently');
         }
 
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $indexes = [['key' => ['lastAccess' => 1], 'expireAfterSeconds' => 3]];
         $createIndexes = new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), $indexes);
diff --git a/tests/Operation/RenameCollectionFunctionalTest.php b/tests/Operation/RenameCollectionFunctionalTest.php
index 5f4b25b6a..21a88e25d 100644
--- a/tests/Operation/RenameCollectionFunctionalTest.php
+++ b/tests/Operation/RenameCollectionFunctionalTest.php
@@ -3,7 +3,6 @@
 namespace MongoDB\Tests\Operation;
 
 use MongoDB\Driver\Exception\CommandException;
-use MongoDB\Operation\DropCollection;
 use MongoDB\Operation\FindOne;
 use MongoDB\Operation\InsertOne;
 use MongoDB\Operation\RenameCollection;
@@ -25,18 +24,8 @@ public function setUp(): void
         parent::setUp();
 
         $this->toCollectionName = $this->getCollectionName() . '.renamed';
-        $operation = new DropCollection($this->getDatabaseName(), $this->toCollectionName);
-        $operation->execute($this->getPrimaryServer());
-    }
-
-    public function tearDown(): void
-    {
-        if (! $this->hasFailed()) {
-            $operation = new DropCollection($this->getDatabaseName(), $this->toCollectionName);
-            $operation->execute($this->getPrimaryServer());
-        }
-
-        parent::tearDown();
+        $this->dropCollection($this->getDatabaseName(), $this->toCollectionName);
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 
     public function testDefaultWriteConcernIsOmitted(): void
diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php
index dc1e12c8b..66c8d85bd 100644
--- a/tests/Operation/WatchFunctionalTest.php
+++ b/tests/Operation/WatchFunctionalTest.php
@@ -52,7 +52,7 @@ public function setUp(): void
         parent::setUp();
 
         $this->skipIfChangeStreamIsNotSupported();
-        $this->createCollection();
+        $this->createCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 
     /**
@@ -1189,7 +1189,7 @@ public function testSessionFreed(): void
         $this->assertIsCallable($rp->getValue($changeStream));
 
         // Invalidate the cursor to verify that resumeCallable is unset when the cursor is exhausted.
-        $this->dropCollection();
+        $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
 
         $this->advanceCursorUntilValid($changeStream);
 

From bf3633134092e58c211e2db0c5b164795771ee69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 1 Jun 2023 20:52:55 +0200
Subject: [PATCH 299/321] PHPLIB-1128: Move generate_index_name() to private
 method within IndexInput (#1092)

* Move generate_index_name() to private method within IndexInput
* Update psalm baseline
---
 psalm-baseline.xml             |  9 ++++++---
 src/Model/IndexInput.php       | 24 ++++++++++++++++++++++--
 src/functions.php              | 21 ---------------------
 tests/FunctionsTest.php        | 16 ----------------
 tests/Model/IndexInputTest.php | 14 +++++++++++---
 5 files changed, 39 insertions(+), 45 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 1d76ad95b..92355a12d 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -274,9 +274,13 @@
     
       $fieldName
     
-    
+    
       $fieldName
+      $type
     
+    
+      $type
+    
     
       $this->index['name']
     
@@ -774,10 +778,9 @@
       $typeMap['fieldPaths'][$fieldPath]
       $typeMap['fieldPaths'][substr($fieldPath, 0, -2)]
     
-    
+    
       $element[$key]
       $type
-      $type
       $typeMap['fieldPaths'][$fieldPath . '.' . $existingFieldPath]
       $typeMap['fieldPaths'][$fieldPath]
       $value
diff --git a/src/Model/IndexInput.php b/src/Model/IndexInput.php
index 65c3fc2a2..310251fc9 100644
--- a/src/Model/IndexInput.php
+++ b/src/Model/IndexInput.php
@@ -25,7 +25,7 @@
 use function is_int;
 use function is_object;
 use function is_string;
-use function MongoDB\generate_index_name;
+use function MongoDB\document_to_array;
 use function sprintf;
 
 /**
@@ -64,7 +64,7 @@ public function __construct(array $index)
         }
 
         if (! isset($index['name'])) {
-            $index['name'] = generate_index_name($index['key']);
+            $index['name'] = $this->generateIndexName($index['key']);
         }
 
         if (! is_string($index['name'])) {
@@ -92,4 +92,24 @@ public function bsonSerialize(): array
     {
         return $this->index;
     }
+
+    /**
+     * Generate an index name from a key specification.
+     *
+     * @param array|object $document Document containing fields mapped to values,
+     *                               which denote order or an index type
+     * @throws InvalidArgumentException if $document is not an array or object
+     */
+    private function generateIndexName($document): string
+    {
+        $document = document_to_array($document);
+
+        $name = '';
+
+        foreach ($document as $field => $type) {
+            $name .= ($name !== '' ? '_' : '') . $field . '_' . $type;
+        }
+
+        return $name;
+    }
 }
diff --git a/src/functions.php b/src/functions.php
index 498d2dba4..b436d79d1 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -140,27 +140,6 @@ function document_to_array($document): array
     return $document;
 }
 
-/**
- * Generate an index name from a key specification.
- *
- * @internal
- * @param array|object $document Document containing fields mapped to values,
- *                               which denote order or an index type
- * @throws InvalidArgumentException if $document is not an array or object
- */
-function generate_index_name($document): string
-{
-    $document = document_to_array($document);
-
-    $name = '';
-
-    foreach ($document as $field => $type) {
-        $name .= ($name != '' ? '_' : '') . $field . '_' . $type;
-    }
-
-    return $name;
-}
-
 /**
  * Return a collection's encryptedFields from the encryptedFieldsMap
  * autoEncryption driver option (if available).
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index 5f1170265..386124627 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -12,7 +12,6 @@
 use function MongoDB\apply_type_map_to_document;
 use function MongoDB\create_field_path_type_map;
 use function MongoDB\document_to_array;
-use function MongoDB\generate_index_name;
 use function MongoDB\is_first_key_operator;
 use function MongoDB\is_last_pipeline_operator_write;
 use function MongoDB\is_mapreduce_output_inline;
@@ -121,14 +120,6 @@ public function testDocumentToArrayArgumentTypeCheck($document): void
         document_to_array($document);
     }
 
-    /** @dataProvider provideDocumentCasts */
-    public function testGenerateIndexName($cast): void
-    {
-        $this->assertSame('x_1', generate_index_name($cast(['x' => 1])));
-        $this->assertSame('x_-1_y_1', generate_index_name($cast(['x' => -1, 'y' => 1])));
-        $this->assertSame('x_2dsphere_y_1', generate_index_name($cast(['x' => '2dsphere', 'y' => 1])));
-    }
-
     public function provideDocumentCasts(): array
     {
         // phpcs:disable SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing
@@ -143,13 +134,6 @@ public function provideDocumentCasts(): array
         // phpcs:enable
     }
 
-    /** @dataProvider provideInvalidDocumentValues */
-    public function testGenerateIndexNameArgumentTypeCheck($document): void
-    {
-        $this->expectException(InvalidArgumentException::class);
-        generate_index_name($document);
-    }
-
     /** @dataProvider provideDocumentCasts */
     public function testIsFirstKeyOperator(callable $cast): void
     {
diff --git a/tests/Model/IndexInputTest.php b/tests/Model/IndexInputTest.php
index 8babe75fd..b9653afda 100644
--- a/tests/Model/IndexInputTest.php
+++ b/tests/Model/IndexInputTest.php
@@ -2,8 +2,10 @@
 
 namespace MongoDB\Tests\Model;
 
+use MongoDB\BSON\Document;
 use MongoDB\BSON\Serializable;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Model\IndexInput;
 use MongoDB\Tests\TestCase;
 use stdClass;
@@ -40,16 +42,22 @@ public function testConstructorShouldRequireNameToBeString(): void
         new IndexInput(['key' => ['x' => 1], 'name' => 1]);
     }
 
-    /** @dataProvider provideExpectedNameAndKey */
-    public function testNameGeneration($expectedName, array $key): void
+    /**
+     * @dataProvider provideExpectedNameAndKey
+     * @param array|object $key
+     */
+    public function testNameGeneration($expectedName, $key): void
     {
         $this->assertSame($expectedName, (string) new IndexInput(['key' => $key]));
     }
 
-    public function provideExpectedNameAndKey()
+    public function provideExpectedNameAndKey(): array
     {
         return [
             ['x_1', ['x' => 1]],
+            ['x_1', (object) ['x' => 1]],
+            ['x_1', new BSONDocument(['x' => 1])],
+            ['x_1', Document::fromPHP(['x' => 1])],
             ['x_1_y_-1', ['x' => 1, 'y' => -1]],
             ['loc_2dsphere', ['loc' => '2dsphere']],
             ['loc_2dsphere_x_1', ['loc' => '2dsphere', 'x' => 1]],

From 9a8f40a70ac1b1a3c0d6cef116a973ff2a3bcb8d Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Wed, 7 Jun 2023 03:04:31 +0800
Subject: [PATCH 300/321] PHPLIB-1156: Use more flexible getMore cursor ID
 assertions (#1089)

Synced with mongodb/specifications@2a51e9827a10e61617b1c34c53377edeed0f6a7b
---
 .../client-side-encryption/tests/getMore.json |  5 +-
 .../load-balancers/cursors.json               | 55 +++++++++++++++----
 .../valid-pass/entity-cursor-iterateOnce.json |  5 +-
 .../valid-pass/entity-find-cursor.json        | 15 ++++-
 4 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/tests/SpecTests/client-side-encryption/tests/getMore.json b/tests/SpecTests/client-side-encryption/tests/getMore.json
index ee99bf753..94e788ef6 100644
--- a/tests/SpecTests/client-side-encryption/tests/getMore.json
+++ b/tests/SpecTests/client-side-encryption/tests/getMore.json
@@ -216,7 +216,10 @@
           "command_started_event": {
             "command": {
               "getMore": {
-                "$$type": "long"
+                "$$type": [
+                  "int",
+                  "long"
+                ]
               },
               "collection": "default",
               "batchSize": 2
diff --git a/tests/UnifiedSpecTests/load-balancers/cursors.json b/tests/UnifiedSpecTests/load-balancers/cursors.json
index 8454f130d..b11bf2c6f 100644
--- a/tests/UnifiedSpecTests/load-balancers/cursors.json
+++ b/tests/UnifiedSpecTests/load-balancers/cursors.json
@@ -222,7 +222,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "firstBatch": {
                       "$$type": "array"
@@ -239,7 +242,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
@@ -333,7 +339,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "firstBatch": {
                       "$$type": "array"
@@ -475,7 +484,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "firstBatch": {
                       "$$type": "array"
@@ -492,7 +504,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
@@ -605,7 +620,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "firstBatch": {
                       "$$type": "array"
@@ -750,7 +768,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "firstBatch": {
                       "$$type": "array"
@@ -767,7 +788,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
@@ -858,7 +882,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
@@ -950,7 +977,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": {
                     "$$type": "string"
@@ -1100,7 +1130,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
diff --git a/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json b/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json
index 88fc28e34..b17ae78b9 100644
--- a/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json
+++ b/tests/UnifiedSpecTests/valid-pass/entity-cursor-iterateOnce.json
@@ -93,7 +93,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
diff --git a/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json b/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json
index 85b8f69d7..6f955d81f 100644
--- a/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json
+++ b/tests/UnifiedSpecTests/valid-pass/entity-find-cursor.json
@@ -109,7 +109,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "ns": {
                       "$$type": "string"
@@ -126,7 +129,10 @@
               "commandStartedEvent": {
                 "command": {
                   "getMore": {
-                    "$$type": "long"
+                    "$$type": [
+                      "int",
+                      "long"
+                    ]
                   },
                   "collection": "coll0"
                 },
@@ -138,7 +144,10 @@
                 "reply": {
                   "cursor": {
                     "id": {
-                      "$$type": "long"
+                      "$$type": [
+                        "int",
+                        "long"
+                      ]
                     },
                     "ns": {
                       "$$type": "string"

From 2d29868cbdfb38e9a260997e9f7efedbcd1507bb Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Fri, 9 Jun 2023 22:10:08 +0800
Subject: [PATCH 301/321] PHPLIB-1122: Additional support for BSON objects
 (#1096)

* Support Document for MapReduce $out parameter

Also adds tests for $out deprecations (re: PHPLIB-480) using various document types.

* Support BSON objects for encryptedFields option

CreateEncryptedCollection::createDataKeys() required more intensive changes to support BSON objects at various levels. The handling for PackedArray and array-yielding Serializable objects is modeled after document_to_array().

Tests were intentionally omitted for the state collection names, since custom values are unsupported and the options aren't documented for public use. Adding functional tests to assert options in outgoing 'create' commands seems like overkill.

* Test BSON objects with BulkWrite operations
---
 psalm-baseline.xml                            |   3 +
 src/Operation/CreateEncryptedCollection.php   |  33 ++-
 src/Operation/DropEncryptedCollection.php     |   3 +-
 src/Operation/MapReduce.php                   |   3 +-
 tests/Operation/BulkWriteFunctionalTest.php   | 203 ++++++++++++++++++
 tests/Operation/BulkWriteTest.php             |  49 ++++-
 ...reateEncryptedCollectionFunctionalTest.php |  99 +++++++--
 tests/Operation/InsertOneFunctionalTest.php   |   2 +-
 tests/Operation/MapReduceTest.php             |  27 +++
 9 files changed, 393 insertions(+), 29 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 92355a12d..be0d2150e 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -422,6 +422,9 @@
       ! is_array($encryptedFields['fields'])
       ! is_array($field) && ! is_object($field)
     
+    
+      $this->options['encryptedFields']
+    
   
   
     
diff --git a/src/Operation/CreateEncryptedCollection.php b/src/Operation/CreateEncryptedCollection.php
index 7ebaee1e4..2cfc6503d 100644
--- a/src/Operation/CreateEncryptedCollection.php
+++ b/src/Operation/CreateEncryptedCollection.php
@@ -18,6 +18,8 @@
 namespace MongoDB\Operation;
 
 use MongoDB\BSON\Binary;
+use MongoDB\BSON\PackedArray;
+use MongoDB\BSON\Serializable;
 use MongoDB\Driver\ClientEncryption;
 use MongoDB\Driver\Exception\RuntimeException as DriverRuntimeException;
 use MongoDB\Driver\Server;
@@ -27,6 +29,7 @@
 use function array_key_exists;
 use function is_array;
 use function is_object;
+use function MongoDB\document_to_array;
 use function MongoDB\server_supports_feature;
 
 /**
@@ -87,7 +90,7 @@ public function __construct(string $databaseName, string $collectionName, array
         $this->createCollection = new CreateCollection($databaseName, $collectionName, $options);
 
         /** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */
-        $encryptedFields = (array) $options['encryptedFields'];
+        $encryptedFields = document_to_array($options['encryptedFields']);
         $enxcolOptions = ['clusteredIndex' => ['key' => ['_id' => 1], 'unique' => true]];
 
         $this->createMetadataCollections = [
@@ -118,12 +121,28 @@ public function __construct(string $databaseName, string $collectionName, array
      */
     public function createDataKeys(ClientEncryption $clientEncryption, string $kmsProvider, ?array $masterKey, ?array &$encryptedFields = null): void
     {
-        /** @psalm-var array{fields: list} */
-        $encryptedFields = (array) $this->options['encryptedFields'];
+        /** @psalm-var array{fields: list|Serializable|PackedArray} */
+        $encryptedFields = document_to_array($this->options['encryptedFields']);
 
-        /* NOP if there are no fields to examine. If the type is invalid, defer
-         * to the server to raise an error in execute(). */
-        if (! isset($encryptedFields['fields']) || ! is_array($encryptedFields['fields'])) {
+        // NOP if there are no fields to examine
+        if (! isset($encryptedFields['fields'])) {
+            return;
+        }
+
+        // Allow PackedArray or Serializable object for the fields array
+        if ($encryptedFields['fields'] instanceof PackedArray) {
+            /** @psalm-var array */
+            $encryptedFields['fields'] = $encryptedFields['fields']->toPHP([
+                'array' => 'array',
+                'document' => 'object',
+                'root' => 'array',
+            ]);
+        } elseif ($encryptedFields['fields'] instanceof Serializable) {
+            $encryptedFields['fields'] = $encryptedFields['fields']->bsonSerialize();
+        }
+
+        // Skip invalid types and defer to the server to raise an error
+        if (! is_array($encryptedFields['fields'])) {
             return;
         }
 
@@ -138,7 +157,7 @@ public function createDataKeys(ClientEncryption $clientEncryption, string $kmsPr
                 continue;
             }
 
-            $field = (array) $field;
+            $field = document_to_array($field);
 
             if (array_key_exists('keyId', $field) && $field['keyId'] === null) {
                 $field['keyId'] = $clientEncryption->createDataKey(...$createDataKeyArgs);
diff --git a/src/Operation/DropEncryptedCollection.php b/src/Operation/DropEncryptedCollection.php
index e5abfaf37..027b14bfa 100644
--- a/src/Operation/DropEncryptedCollection.php
+++ b/src/Operation/DropEncryptedCollection.php
@@ -23,6 +23,7 @@
 
 use function is_array;
 use function is_object;
+use function MongoDB\document_to_array;
 
 /**
  * Drop an encrypted collection.
@@ -72,7 +73,7 @@ public function __construct(string $databaseName, string $collectionName, array
         }
 
         /** @psalm-var array{ecocCollection?: ?string, escCollection?: ?string} */
-        $encryptedFields = (array) $options['encryptedFields'];
+        $encryptedFields = document_to_array($options['encryptedFields']);
 
         $this->dropMetadataCollections = [
             new DropCollection($databaseName, $encryptedFields['escCollection'] ?? 'enxcol_.' . $collectionName . '.esc'),
diff --git a/src/Operation/MapReduce.php b/src/Operation/MapReduce.php
index b02dc8142..58d11938f 100644
--- a/src/Operation/MapReduce.php
+++ b/src/Operation/MapReduce.php
@@ -40,6 +40,7 @@
 use function is_object;
 use function is_string;
 use function MongoDB\create_field_path_type_map;
+use function MongoDB\document_to_array;
 use function MongoDB\is_mapreduce_output_inline;
 use function trigger_error;
 
@@ -315,7 +316,7 @@ private function checkOutDeprecations($out): void
             return;
         }
 
-        $out = (array) $out;
+        $out = document_to_array($out);
 
         if (isset($out['nonAtomic']) && ! $out['nonAtomic']) {
             @trigger_error('Specifying false for "out.nonAtomic" is deprecated.', E_USER_DEPRECATED);
diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php
index 61d374168..9306427dd 100644
--- a/tests/Operation/BulkWriteFunctionalTest.php
+++ b/tests/Operation/BulkWriteFunctionalTest.php
@@ -2,16 +2,21 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\BSON\ObjectId;
+use MongoDB\BSON\PackedArray;
 use MongoDB\BulkWriteResult;
 use MongoDB\Collection;
 use MongoDB\Driver\BulkWrite as Bulk;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\BadMethodCallException;
+use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\BulkWrite;
 use MongoDB\Tests\CommandObserver;
+use stdClass;
 
+use function is_array;
 use function version_compare;
 
 class BulkWriteFunctionalTest extends FunctionalTestCase
@@ -57,6 +62,60 @@ public function testInserts(): void
         $this->assertSameDocuments($expected, $this->collection->find());
     }
 
+    /**
+     * @dataProvider provideDocumentsWithIds
+     * @dataProvider provideDocumentsWithoutIds
+     */
+    public function testInsertDocumentEncoding($document, stdClass $expectedDocument): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($document, $expectedDocument): void {
+                $operation = new BulkWrite(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [['insertOne' => [$document]]]
+                );
+
+                $result = $operation->execute($this->getPrimaryServer());
+
+                // Replace _id placeholder if necessary
+                if ($expectedDocument->_id === null) {
+                    $expectedDocument->_id = $result->getInsertedIds()[0];
+                }
+            },
+            function (array $event) use ($expectedDocument): void {
+                $this->assertEquals($expectedDocument, $event['started']->getCommand()->documents[0] ?? null);
+            }
+        );
+    }
+
+    public function provideDocumentsWithIds(): array
+    {
+        $expectedDocument = (object) ['_id' => 1];
+
+        return [
+            'with_id:array' => [['_id' => 1], $expectedDocument],
+            'with_id:object' => [(object) ['_id' => 1], $expectedDocument],
+            'with_id:Serializable' => [new BSONDocument(['_id' => 1]), $expectedDocument],
+            'with_id:Document' => [Document::fromPHP(['_id' => 1]), $expectedDocument],
+        ];
+    }
+
+    public function provideDocumentsWithoutIds(): array
+    {
+        /* Note: _id placeholders must be replaced with generated ObjectIds. We
+         * also clone the value for each data set since tests may need to modify
+         * the object. */
+        $expectedDocument = (object) ['_id' => null, 'x' => 1];
+
+        return [
+            'without_id:array' => [['x' => 1], clone $expectedDocument],
+            'without_id:object' => [(object) ['x' => 1], clone $expectedDocument],
+            'without_id:Serializable' => [new BSONDocument(['x' => 1]), clone $expectedDocument],
+            'without_id:Document' => [Document::fromPHP(['x' => 1]), clone $expectedDocument],
+        ];
+    }
+
     public function testUpdates(): void
     {
         $this->createFixtures(4);
@@ -93,6 +152,127 @@ public function testUpdates(): void
         $this->assertSameDocuments($expected, $this->collection->find());
     }
 
+    /** @dataProvider provideFilterDocuments */
+    public function testUpdateFilterDocuments($filter, stdClass $expectedFilter): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new BulkWrite(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [
+                        ['replaceOne' => [$filter, ['x' => 1]]],
+                        ['updateOne' => [$filter, ['$set' => ['x' => 1]]]],
+                        ['updateMany' => [$filter, ['$set' => ['x' => 1]]]],
+                    ]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedFilter): void {
+                $this->assertEquals($expectedFilter, $event['started']->getCommand()->updates[0]->q ?? null);
+                $this->assertEquals($expectedFilter, $event['started']->getCommand()->updates[1]->q ?? null);
+                $this->assertEquals($expectedFilter, $event['started']->getCommand()->updates[2]->q ?? null);
+            }
+        );
+    }
+
+    public function provideFilterDocuments(): array
+    {
+        $expectedQuery = (object) ['x' => 1];
+
+        return [
+            'array' => [['x' => 1], $expectedQuery],
+            'object' => [(object) ['x' => 1], $expectedQuery],
+            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
+            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
+        ];
+    }
+
+    /** @dataProvider provideReplacementDocuments */
+    public function testReplacementDocuments($replacement, stdClass $expectedReplacement): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($replacement): void {
+                $operation = new BulkWrite(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [['replaceOne' => [['x' => 1], $replacement]]]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedReplacement): void {
+                $this->assertEquals($expectedReplacement, $event['started']->getCommand()->updates[0]->u ?? null);
+            }
+        );
+    }
+
+    public function provideReplacementDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+
+        return [
+            'replacement:array' => [['x' => 1], $expected],
+            'replacement:object' => [(object) ['x' => 1], $expected],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
+        ];
+    }
+
+    /**
+     * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
+     */
+    public function testUpdateDocuments($update, $expectedUpdate): void
+    {
+        if (is_array($expectedUpdate) && version_compare($this->getServerVersion(), '4.2.0', '<')) {
+            $this->markTestSkipped('Pipeline-style updates are not supported');
+        }
+
+        (new CommandObserver())->observe(
+            function () use ($update): void {
+                $operation = new BulkWrite(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [
+                        ['updateOne' => [['x' => 1], $update]],
+                        ['updateMany' => [['x' => 1], $update]],
+                    ]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedUpdate): void {
+                $this->assertEquals($expectedUpdate, $event['started']->getCommand()->updates[0]->u ?? null);
+                $this->assertEquals($expectedUpdate, $event['started']->getCommand()->updates[1]->u ?? null);
+            }
+        );
+    }
+
+    public function provideUpdateDocuments(): array
+    {
+        $expected = (object) ['$set' => (object) ['x' => 1]];
+
+        return [
+            'update:array' => [['$set' => ['x' => 1]], $expected],
+            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
+        ];
+    }
+
+    public function provideUpdatePipelines(): array
+    {
+        $expected = [(object) ['$set' => (object) ['x' => 1]]];
+
+        return [
+            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
+            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
+            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
+        ];
+    }
+
     public function testDeletes(): void
     {
         $this->createFixtures(4);
@@ -115,6 +295,29 @@ public function testDeletes(): void
         $this->assertSameDocuments($expected, $this->collection->find());
     }
 
+    /** @dataProvider provideFilterDocuments */
+    public function testDeleteFilterDocuments($filter, stdClass $expectedQuery): void
+    {
+        (new CommandObserver())->observe(
+            function () use ($filter): void {
+                $operation = new BulkWrite(
+                    $this->getDatabaseName(),
+                    $this->getCollectionName(),
+                    [
+                        ['deleteOne' => [$filter]],
+                        ['deleteMany' => [$filter]],
+                    ]
+                );
+
+                $operation->execute($this->getPrimaryServer());
+            },
+            function (array $event) use ($expectedQuery): void {
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->deletes[0]->q ?? null);
+                $this->assertEquals($expectedQuery, $event['started']->getCommand()->deletes[1]->q ?? null);
+            }
+        );
+    }
+
     public function testMixedOrderedOperations(): void
     {
         $this->createFixtures(3);
diff --git a/tests/Operation/BulkWriteTest.php b/tests/Operation/BulkWriteTest.php
index 65a6ab7cb..31b90d86b 100644
--- a/tests/Operation/BulkWriteTest.php
+++ b/tests/Operation/BulkWriteTest.php
@@ -2,7 +2,11 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\BulkWrite;
 
 class BulkWriteTest extends TestCase
@@ -164,15 +168,33 @@ public function testReplaceOneReplacementArgumentTypeCheck($replacement): void
         ]);
     }
 
-    public function testReplaceOneReplacementArgumentRequiresNoOperators(): void
+    /** @dataProvider provideInvalidReplacementValues */
+    public function testReplaceOneReplacementArgumentRequiresNoOperators($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->expectExceptionMessage('First key in $operations[0]["replaceOne"][1] is an update operator');
         new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
-            [BulkWrite::REPLACE_ONE => [['_id' => 1], ['$inc' => ['x' => 1]]]],
+            [BulkWrite::REPLACE_ONE => [['x' => 1], $replacement]],
         ]);
     }
 
+    public function provideInvalidReplacementValues(): array
+    {
+        return [
+            'update:array' => [['$set' => ['x' => 1]]],
+            'update:object' => [(object) ['$set' => ['x' => 1]]],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
+            // TODO: Enable the following tests when implementing PHPLIB-1129
+            //'pipeline:array' => [[['$set' => ['x' => 1]]]],
+            //'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
+            //'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
+            //'empty_pipeline:array' => [[]],
+            //'empty_pipeline:Serializable' => [new BSONArray([])],
+            //'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
+
     /** @dataProvider provideInvalidDocumentValues */
     public function testReplaceOneCollationOptionTypeCheck($collation): void
     {
@@ -236,15 +258,29 @@ public function testUpdateManyUpdateArgumentTypeCheck($update): void
         ]);
     }
 
-    public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline(): void
+    /** @dataProvider provideInvalidUpdateValues */
+    public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->expectExceptionMessage('First key in $operations[0]["updateMany"][1] is neither an update operator nor a pipeline');
         new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
-            [BulkWrite::UPDATE_MANY => [['_id' => ['$gt' => 1]], ['x' => 1]]],
+            [BulkWrite::UPDATE_MANY => [['x' => 1], $update]],
         ]);
     }
 
+    public function provideInvalidUpdateValues(): array
+    {
+        return [
+            'replacement:array' => [['x' => 1]],
+            'replacement:object' => [(object) ['x' => 1]],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
+            'replacement:Document' => [Document::fromPHP(['x' => 1])],
+            'empty_pipeline:array' => [[]],
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
+
     /** @dataProvider provideInvalidArrayValues */
     public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void
     {
@@ -313,12 +349,13 @@ public function testUpdateOneUpdateArgumentTypeCheck($update): void
         ]);
     }
 
-    public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline(): void
+    /** @dataProvider provideInvalidUpdateValues */
+    public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->expectExceptionMessage('First key in $operations[0]["updateOne"][1] is neither an update operator nor a pipeline');
         new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
-            [BulkWrite::UPDATE_ONE => [['_id' => 1], ['x' => 1]]],
+            [BulkWrite::UPDATE_ONE => [['x' => 1], $update]],
         ]);
     }
 
diff --git a/tests/Operation/CreateEncryptedCollectionFunctionalTest.php b/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
index cdf9ac31d..df690dd29 100644
--- a/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
+++ b/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
@@ -3,9 +3,12 @@
 namespace MongoDB\Tests\Operation;
 
 use MongoDB\BSON\Binary;
+use MongoDB\BSON\Document;
 use MongoDB\Client;
 use MongoDB\ClientEncryption;
 use MongoDB\Driver\WriteConcern;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\CreateEncryptedCollection;
 
 use function base64_decode;
@@ -61,61 +64,100 @@ public function setUp(): void
         ]);
     }
 
-    public function testCreateDataKeysNopIfFieldsArrayIsMissing(): void
+    /** @dataProvider provideEncryptedFieldsAndFieldsIsMissing */
+    public function testCreateDataKeysNopIfFieldsIsMissing($input, array $expectedOutput): void
     {
         $operation = new CreateEncryptedCollection(
             $this->getDatabaseName(),
             $this->getCollectionName(),
-            ['encryptedFields' => []]
+            ['encryptedFields' => $input]
         );
 
         $operation->createDataKeys(
             $this->clientEncryption,
             'local',
             null,
-            $encryptedFields
+            $encryptedFieldsOutput
         );
 
-        $this->assertSame([], $encryptedFields);
+        $this->assertSame($expectedOutput, $encryptedFieldsOutput);
     }
 
-    public function testCreateDataKeysNopIfFieldsArrayIsInvalid(): void
+    public function provideEncryptedFieldsAndFieldsIsMissing(): array
+    {
+        $ef = [];
+
+        return [
+            'array' => [$ef, $ef],
+            'object' => [(object) $ef, $ef],
+            'Serializable' => [new BSONDocument($ef), $ef],
+            'Document' => [Document::fromPHP($ef), $ef],
+        ];
+    }
+
+    /** @dataProvider provideEncryptedFieldsAndFieldsHasInvalidType */
+    public function testCreateDataKeysNopIfFieldsHasInvalidType($input, array $expectedOutput): void
     {
         $operation = new CreateEncryptedCollection(
             $this->getDatabaseName(),
             $this->getCollectionName(),
-            ['encryptedFields' => ['fields' => 'not-an-array']]
+            ['encryptedFields' => $input]
         );
 
         $operation->createDataKeys(
             $this->clientEncryption,
             'local',
             null,
-            $encryptedFields
+            $encryptedFieldsOutput
         );
 
-        $this->assertSame(['fields' => 'not-an-array'], $encryptedFields);
+        $this->assertSame($expectedOutput, $encryptedFieldsOutput);
     }
 
-    public function testCreateDataKeysSkipsNonDocumentFields(): void
+    public function provideEncryptedFieldsAndFieldsHasInvalidType(): array
+    {
+        $ef = ['fields' => 'not-an-array'];
+
+        return [
+            'array' => [$ef, $ef],
+            'object' => [(object) $ef, $ef],
+            'Serializable' => [new BSONDocument($ef), $ef],
+            'Document' => [Document::fromPHP($ef), $ef],
+        ];
+    }
+
+    /** @dataProvider provideEncryptedFieldsElementHasInvalidType */
+    public function testCreateDataKeysSkipsNonDocumentFields($input, array $expectedOutput): void
     {
         $operation = new CreateEncryptedCollection(
             $this->getDatabaseName(),
             $this->getCollectionName(),
-            ['encryptedFields' => ['fields' => ['not-an-array-or-object']]]
+            ['encryptedFields' => $input]
         );
 
         $operation->createDataKeys(
             $this->clientEncryption,
             'local',
             null,
-            $encryptedFields
+            $encryptedFieldsOutput
         );
 
-        $this->assertSame(['fields' => ['not-an-array-or-object']], $encryptedFields);
+        $this->assertSame($expectedOutput, $encryptedFieldsOutput);
+    }
+
+    public function provideEncryptedFieldsElementHasInvalidType(): array
+    {
+        $ef = ['fields' => ['not-an-array-or-object']];
+
+        return [
+            'array' => [$ef, $ef],
+            'object' => [(object) $ef, $ef],
+            'Serializable' => [new BSONDocument(['fields' => new BSONArray(['not-an-array-or-object'])]), $ef],
+            'Document' => [Document::fromPHP($ef), $ef],
+        ];
     }
 
-    public function testCreateDataKeysDoesNotModifyEncryptedFieldsObjectOption(): void
+    public function testCreateDataKeysDoesNotModifyOriginalEncryptedFieldsOption(): void
     {
         $originalField = (object) ['path' => 'ssn', 'bsonType' => 'string', 'keyId' => null];
         $originalEncryptedFields = (object) ['fields' => [$originalField]];
@@ -139,6 +181,37 @@ public function testCreateDataKeysDoesNotModifyEncryptedFieldsObjectOption(): vo
         $this->assertInstanceOf(Binary::class, $modifiedEncryptedFields['fields'][0]['keyId'] ?? null);
     }
 
+    /** @dataProvider provideEncryptedFields */
+    public function testEncryptedFieldsDocuments($input): void
+    {
+        $operation = new CreateEncryptedCollection(
+            $this->getDatabaseName(),
+            $this->getCollectionName(),
+            ['encryptedFields' => $input]
+        );
+
+        $operation->createDataKeys(
+            $this->clientEncryption,
+            'local',
+            null,
+            $modifiedEncryptedFields
+        );
+
+        $this->assertInstanceOf(Binary::class, $modifiedEncryptedFields['fields'][0]['keyId'] ?? null);
+    }
+
+    public function provideEncryptedFields(): array
+    {
+        $ef = ['fields' => [['path' => 'ssn', 'bsonType' => 'string', 'keyId' => null]]];
+
+        return [
+            'array' => [$ef],
+            'object' => [(object) $ef],
+            'Serializable' => [new BSONDocument(['fields' => new BSONArray([new BSONDocument($ef['fields'][0])])])],
+            'Document' => [Document::fromPHP($ef)],
+        ];
+    }
+
     public static function createTestClient(?string $uri = null, array $options = [], array $driverOptions = []): Client
     {
         if (isset($driverOptions['autoEncryption']) && getenv('CRYPT_SHARED_LIB_PATH')) {
diff --git a/tests/Operation/InsertOneFunctionalTest.php b/tests/Operation/InsertOneFunctionalTest.php
index ce2dcdf3f..61a517894 100644
--- a/tests/Operation/InsertOneFunctionalTest.php
+++ b/tests/Operation/InsertOneFunctionalTest.php
@@ -67,7 +67,7 @@ public function provideDocumentsWithIds(): array
     public function provideDocumentsWithoutIds(): array
     {
         /* Note: _id placeholders must be replaced with generated ObjectIds. We
-         * also clone the value for each data set since tests will may modify
+         * also clone the value for each data set since tests may need to modify
          * the object. */
         $expectedDocument = (object) ['_id' => null, 'x' => 1];
 
diff --git a/tests/Operation/MapReduceTest.php b/tests/Operation/MapReduceTest.php
index 88d4a77fd..2f155aa84 100644
--- a/tests/Operation/MapReduceTest.php
+++ b/tests/Operation/MapReduceTest.php
@@ -2,9 +2,11 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
 use MongoDB\BSON\Javascript;
 use MongoDB\BSON\ObjectId;
 use MongoDB\Exception\InvalidArgumentException;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\MapReduce;
 use stdClass;
 
@@ -25,6 +27,31 @@ public function provideInvalidOutValues()
         return $this->wrapValuesForDataProvider([123, 3.14, true]);
     }
 
+    /** @dataProvider provideDeprecatedOutValues */
+    public function testConstructorOutArgumentDeprecations($out): void
+    {
+        $map = new Javascript('function() { emit(this.x, this.y); }');
+        $reduce = new Javascript('function(key, values) { return Array.sum(values); }');
+
+        $this->assertDeprecated(function () use ($map, $reduce, $out): void {
+            new MapReduce($this->getDatabaseName(), $this->getCollectionName(), $map, $reduce, $out);
+        });
+    }
+
+    public function provideDeprecatedOutValues(): array
+    {
+        return [
+            'nonAtomic:array' => [['nonAtomic' => false]],
+            'nonAtomic:object' => [(object) ['nonAtomic' => false]],
+            'nonAtomic:Serializable' => [new BSONDocument(['nonAtomic' => false])],
+            'nonAtomic:Document' => [Document::fromPHP(['nonAtomic' => false])],
+            'sharded:array' => [['sharded' => false]],
+            'sharded:object' => [(object) ['sharded' => false]],
+            'sharded:Serializable' => [new BSONDocument(['sharded' => false])],
+            'sharded:Document' => [Document::fromPHP(['sharded' => false])],
+        ];
+    }
+
     /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {

From 14c22fd472ef1e431670b9e4166a95032b41a95e Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Sat, 10 Jun 2023 04:09:55 +0800
Subject: [PATCH 302/321] PHPLIB-1129: Improve pipeline checks for replace
 operations (#1098)

* Improve pipeline checks for replace operations

Consolidates data providers in base TestCase and FunctionalTestCase classes.

Change is_pipeline() to conditionally consider empty arrays as pipelines. This was needed for improvements to replace/update parameter validation, and will prove useful for consolidated pipeline validation in PHPLIB-881.

Prohibit update documents and pipelines (both empty and non-empty) for replacement operations.

Prohibit replacement documents and empty pipeines for update operations. Empty pipelines must be prohibited because libmongoc does not support them for update commands (they're indistinguishable from empty replacement documents). For consistency, we also prohibit them for FindOneAndUpdate even though PHPLIB could work around that.

Prohibit update pipelines for replace operations (both empty and non-empty). Previously ReplaceOne only prohibited non-empty pipelines and BulkWrite replaceOne and FindOneAndReplace has no validation. A notable exception is empty arrays, which are treated as replacement documents for BC.

Add tests for valid update/replacement arguments for BulkWrite replaceOne, updateMany, and updateOne operations. Also adds more comprehensive tests for valid $update arguments for UpdateMany and UpdateOne operations (update documents and non-empty pipelines).

* Demonstrate edge case where replacement doc encodes as pipeline array

* Test FindAndModify with replacement doc resembling a pipeline

Note that FindAndModify's behavior differs from Update since it is unaffected by libmongoc's pipeline detection for update commands. FindAndModify behaves correctly.

Add a comment explaining how the conditional object cast in FindAndModify::createCommandDocument() affects BSON encoding for the update option.
---
 psalm-baseline.xml                            | 14 ++-
 src/Operation/BulkWrite.php                   | 11 ++-
 src/Operation/FindAndModify.php               |  8 ++
 src/Operation/FindOneAndReplace.php           | 12 ++-
 src/Operation/FindOneAndUpdate.php            |  2 +-
 src/Operation/ReplaceOne.php                  | 11 ++-
 src/Operation/Update.php                      |  2 +-
 src/Operation/UpdateMany.php                  |  2 +-
 src/Operation/UpdateOne.php                   |  2 +-
 src/functions.php                             | 23 ++++-
 tests/Operation/BulkWriteFunctionalTest.php   | 49 ----------
 tests/Operation/BulkWriteTest.php             | 98 +++++++++++--------
 .../CountDocumentsFunctionalTest.php          | 14 ---
 tests/Operation/CountFunctionalTest.php       | 14 ---
 tests/Operation/DeleteFunctionalTest.php      | 14 ---
 tests/Operation/DistinctFunctionalTest.php    | 14 ---
 .../Operation/FindAndModifyFunctionalTest.php | 41 ++------
 tests/Operation/FindFunctionalTest.php        | 12 ---
 tests/Operation/FindOneAndReplaceTest.php     | 41 ++++----
 tests/Operation/FindOneAndUpdateTest.php      | 26 ++---
 tests/Operation/FunctionalTestCase.php        | 62 ++++++++++++
 tests/Operation/ReplaceOneTest.php            | 41 +++-----
 tests/Operation/TestCase.php                  | 65 ++++++++++++
 tests/Operation/UpdateFunctionalTest.php      | 54 ++--------
 tests/Operation/UpdateManyTest.php            | 36 ++-----
 tests/Operation/UpdateOneTest.php             | 36 ++-----
 tests/Operation/UpdateTest.php                | 26 ++---
 27 files changed, 330 insertions(+), 400 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index be0d2150e..ead3a341c 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -36,8 +36,9 @@
     
   
   
-    
+    
       new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, get_debug_type($value)))
+      new static('Expected update operator(s) or non-empty pipeline for ' . $name)
     
   
   
@@ -308,7 +309,7 @@
     
       is_array($operation)
     
-    
+    
       $args
       $args
       $args
@@ -320,9 +321,10 @@
       $args[1]
       $args[1]
       $args[1]
+      $args[1]
       $args[2]
     
-    
+    
       $args[0]
       $args[0]
       $args[0]
@@ -337,6 +339,9 @@
       $args[1]
       $args[1]
       $args[1]
+      $args[1]
+      $args[1]
+      $args[1]
       $args[2]
       $args[2]
       $args[2]
@@ -349,7 +354,8 @@
       $args[2]['upsert']
       $args[2]['upsert']
     
-    
+    
+      $args[1]
       $args[1]
       $args[1]
       $args[2]
diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php
index 2296007dd..b68daed4d 100644
--- a/src/Operation/BulkWrite.php
+++ b/src/Operation/BulkWrite.php
@@ -191,10 +191,19 @@ public function __construct(string $databaseName, string $collectionName, array
                         throw InvalidArgumentException::invalidType(sprintf('$operations[%d]["%s"][1]', $i, $type), $args[1], 'array or object');
                     }
 
+                    // Treat empty arrays as replacement documents for BC
+                    if ($args[1] === []) {
+                        $args[1] = (object) $args[1];
+                    }
+
                     if (is_first_key_operator($args[1])) {
                         throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is an update operator', $i, $type));
                     }
 
+                    if (is_pipeline($args[1], true /* allowEmpty */)) {
+                        throw new InvalidArgumentException(sprintf('$operations[%d]["%s"][1] is an update pipeline', $i, $type));
+                    }
+
                     if (! isset($args[2])) {
                         $args[2] = [];
                     }
@@ -229,7 +238,7 @@ public function __construct(string $databaseName, string $collectionName, array
                     }
 
                     if (! is_first_key_operator($args[1]) && ! is_pipeline($args[1])) {
-                        throw new InvalidArgumentException(sprintf('First key in $operations[%d]["%s"][1] is neither an update operator nor a pipeline', $i, $type));
+                        throw new InvalidArgumentException(sprintf('Expected update operator(s) or non-empty pipeline for $operations[%d]["%s"][1]', $i, $type));
                     }
 
                     if (! isset($args[2])) {
diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php
index cb97637f7..88f411362 100644
--- a/src/Operation/FindAndModify.php
+++ b/src/Operation/FindAndModify.php
@@ -295,6 +295,14 @@ private function createCommandDocument(): array
         if (isset($this->options['update'])) {
             /** @psalm-var array|object */
             $update = $this->options['update'];
+            /* A non-empty pipeline will encode as a BSON array, so leave it
+             * as-is. Cast anything else to an object since a BSON document is
+             * likely expected. This includes empty arrays, which historically
+             * can be used to represent empty replacement documents.
+             *
+             * This also allows an empty pipeline expressed as a PackedArray or
+             * Serializable to still encode as a BSON array, since the object
+             * cast will have no effect. */
             $cmd['update'] = is_pipeline($update) ? $update : (object) $update;
         }
 
diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php
index 46b0bd5d3..4132985cd 100644
--- a/src/Operation/FindOneAndReplace.php
+++ b/src/Operation/FindOneAndReplace.php
@@ -27,6 +27,7 @@
 use function is_integer;
 use function is_object;
 use function MongoDB\is_first_key_operator;
+use function MongoDB\is_pipeline;
 
 /**
  * Operation for replacing a document with the findAndModify command.
@@ -109,8 +110,17 @@ public function __construct(string $databaseName, string $collectionName, $filte
             throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object');
         }
 
+        // Treat empty arrays as replacement documents for BC
+        if ($replacement === []) {
+            $replacement = (object) $replacement;
+        }
+
         if (is_first_key_operator($replacement)) {
-            throw new InvalidArgumentException('First key in $replacement argument is an update operator');
+            throw new InvalidArgumentException('First key in $replacement is an update operator');
+        }
+
+        if (is_pipeline($replacement, true /* allowEmpty */)) {
+            throw new InvalidArgumentException('$replacement is an update pipeline');
         }
 
         if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) {
diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php
index adc0ae24c..88bea8bd9 100644
--- a/src/Operation/FindOneAndUpdate.php
+++ b/src/Operation/FindOneAndUpdate.php
@@ -114,7 +114,7 @@ public function __construct(string $databaseName, string $collectionName, $filte
         }
 
         if (! is_first_key_operator($update) && ! is_pipeline($update)) {
-            throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline');
+            throw new InvalidArgumentException('Expected update operator(s) or non-empty pipeline for $update');
         }
 
         if (isset($options['projection']) && ! is_array($options['projection']) && ! is_object($options['projection'])) {
diff --git a/src/Operation/ReplaceOne.php b/src/Operation/ReplaceOne.php
index ce794f9c7..a2b641aa8 100644
--- a/src/Operation/ReplaceOne.php
+++ b/src/Operation/ReplaceOne.php
@@ -85,12 +85,17 @@ public function __construct(string $databaseName, string $collectionName, $filte
             throw InvalidArgumentException::invalidType('$replacement', $replacement, 'array or object');
         }
 
+        // Treat empty arrays as replacement documents for BC
+        if ($replacement === []) {
+            $replacement = (object) $replacement;
+        }
+
         if (is_first_key_operator($replacement)) {
-            throw new InvalidArgumentException('First key in $replacement argument is an update operator');
+            throw new InvalidArgumentException('First key in $replacement is an update operator');
         }
 
-        if (is_pipeline($replacement)) {
-            throw new InvalidArgumentException('$replacement argument is a pipeline');
+        if (is_pipeline($replacement, true /* allowEmpty */)) {
+            throw new InvalidArgumentException('$replacement is an update pipeline');
         }
 
         $this->update = new Update(
diff --git a/src/Operation/Update.php b/src/Operation/Update.php
index 611d581d2..a6bd8f441 100644
--- a/src/Operation/Update.php
+++ b/src/Operation/Update.php
@@ -148,7 +148,7 @@ public function __construct(string $databaseName, string $collectionName, $filte
         }
 
         if ($options['multi'] && ! is_first_key_operator($update) && ! is_pipeline($update)) {
-            throw new InvalidArgumentException('"multi" option cannot be true if $update is a replacement document');
+            throw new InvalidArgumentException('"multi" option cannot be true unless $update has update operator(s) or non-empty pipeline');
         }
 
         if (isset($options['session']) && ! $options['session'] instanceof Session) {
diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php
index b751c1c51..a7002baf5 100644
--- a/src/Operation/UpdateMany.php
+++ b/src/Operation/UpdateMany.php
@@ -89,7 +89,7 @@ public function __construct(string $databaseName, string $collectionName, $filte
         }
 
         if (! is_first_key_operator($update) && ! is_pipeline($update)) {
-            throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline');
+            throw new InvalidArgumentException('Expected update operator(s) or non-empty pipeline for $update');
         }
 
         $this->update = new Update(
diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php
index ab57defbc..63436c0e7 100644
--- a/src/Operation/UpdateOne.php
+++ b/src/Operation/UpdateOne.php
@@ -89,7 +89,7 @@ public function __construct(string $databaseName, string $collectionName, $filte
         }
 
         if (! is_first_key_operator($update) && ! is_pipeline($update)) {
-            throw new InvalidArgumentException('Expected an update document with operator as first key or a pipeline');
+            throw new InvalidArgumentException('Expected update operator(s) or non-empty pipeline for $update');
         }
 
         $this->update = new Update(
diff --git a/src/functions.php b/src/functions.php
index b436d79d1..95f9cc9a1 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -213,7 +213,22 @@ function is_first_key_operator($document): bool
 }
 
 /**
- * Returns whether an update specification is a valid aggregation pipeline.
+ * Returns whether the argument is a valid aggregation or update pipeline.
+ *
+ * This is primarily used for validating arguments for update and replace
+ * operations, but can also be used for validating an aggregation pipeline.
+ *
+ * The $allowEmpty parameter can be used to control whether an empty array
+ * should be considered a valid pipeline. Empty arrays are generally valid for
+ * an aggregation pipeline, but the things are more complicated for update
+ * pipelines.
+ *
+ * Update operations must prohibit empty pipelines, since libmongoc may encode
+ * an empty pipeline array as an empty replacement document when writing an
+ * update command (arrays and documents have the same bson_t representation).
+ * For consistency, findOneAndUpdate should also prohibit empty pipelines.
+ * Replace operations (e.g. replaceOne, findOneAndReplace) should reject empty
+ * and non-empty pipelines alike, since neither is a replacement document.
  *
  * Note: this method may propagate an InvalidArgumentException from
  * document_or_array() if a Serializable object within the pipeline array
@@ -223,11 +238,11 @@ function is_first_key_operator($document): bool
  * @param array|object $pipeline
  * @throws InvalidArgumentException
  */
-function is_pipeline($pipeline): bool
+function is_pipeline($pipeline, bool $allowEmpty = false): bool
 {
     if ($pipeline instanceof PackedArray) {
         /* Nested documents and arrays are intentionally left as BSON. We avoid
-         * iterator_to_array() since Document iteration returns all values as
+         * iterator_to_array() since PackedArray iteration returns all values as
          * MongoDB\BSON\Value instances. */
         /** @psalm-var array */
         $pipeline = $pipeline->toPHP([
@@ -244,7 +259,7 @@ function is_pipeline($pipeline): bool
     }
 
     if ($pipeline === []) {
-        return false;
+        return $allowEmpty;
     }
 
     $expectedKey = 0;
diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php
index 9306427dd..0dbb20e67 100644
--- a/tests/Operation/BulkWriteFunctionalTest.php
+++ b/tests/Operation/BulkWriteFunctionalTest.php
@@ -4,13 +4,11 @@
 
 use MongoDB\BSON\Document;
 use MongoDB\BSON\ObjectId;
-use MongoDB\BSON\PackedArray;
 use MongoDB\BulkWriteResult;
 use MongoDB\Collection;
 use MongoDB\Driver\BulkWrite as Bulk;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\BadMethodCallException;
-use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\BulkWrite;
 use MongoDB\Tests\CommandObserver;
@@ -177,18 +175,6 @@ function (array $event) use ($expectedFilter): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expectedQuery = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expectedQuery],
-            'object' => [(object) ['x' => 1], $expectedQuery],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
-            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
-        ];
-    }
-
     /** @dataProvider provideReplacementDocuments */
     public function testReplacementDocuments($replacement, stdClass $expectedReplacement): void
     {
@@ -208,18 +194,6 @@ function (array $event) use ($expectedReplacement): void {
         );
     }
 
-    public function provideReplacementDocuments(): array
-    {
-        $expected = (object) ['x' => 1];
-
-        return [
-            'replacement:array' => [['x' => 1], $expected],
-            'replacement:object' => [(object) ['x' => 1], $expected],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
-            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
-        ];
-    }
-
     /**
      * @dataProvider provideUpdateDocuments
      * @dataProvider provideUpdatePipelines
@@ -250,29 +224,6 @@ function (array $event) use ($expectedUpdate): void {
         );
     }
 
-    public function provideUpdateDocuments(): array
-    {
-        $expected = (object) ['$set' => (object) ['x' => 1]];
-
-        return [
-            'update:array' => [['$set' => ['x' => 1]], $expected],
-            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
-            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
-            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
-        ];
-    }
-
-    public function provideUpdatePipelines(): array
-    {
-        $expected = [(object) ['$set' => (object) ['x' => 1]]];
-
-        return [
-            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
-            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
-            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
-        ];
-    }
-
     public function testDeletes(): void
     {
         $this->createFixtures(4);
diff --git a/tests/Operation/BulkWriteTest.php b/tests/Operation/BulkWriteTest.php
index 31b90d86b..ac21e558e 100644
--- a/tests/Operation/BulkWriteTest.php
+++ b/tests/Operation/BulkWriteTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\BulkWrite;
 
 class BulkWriteTest extends TestCase
@@ -149,6 +145,17 @@ public function testReplaceOneFilterArgumentTypeCheck($filter): void
         ]);
     }
 
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @doesNotPerformAssertions
+     */
+    public function testReplaceOneReplacementArgument($replacement): void
+    {
+        new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
+            [BulkWrite::REPLACE_ONE => [['x' => 1], $replacement]],
+        ]);
+    }
+
     public function testReplaceOneReplacementArgumentMissing(): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -168,8 +175,8 @@ public function testReplaceOneReplacementArgumentTypeCheck($replacement): void
         ]);
     }
 
-    /** @dataProvider provideInvalidReplacementValues */
-    public function testReplaceOneReplacementArgumentRequiresNoOperators($replacement): void
+    /** @dataProvider provideUpdateDocuments */
+    public function testReplaceOneReplacementArgumentProhibitsUpdateDocument($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
         $this->expectExceptionMessage('First key in $operations[0]["replaceOne"][1] is an update operator');
@@ -178,21 +185,17 @@ public function testReplaceOneReplacementArgumentRequiresNoOperators($replacemen
         ]);
     }
 
-    public function provideInvalidReplacementValues(): array
+    /**
+     * @dataProvider provideUpdatePipelines
+     * @dataProvider provideEmptyUpdatePipelinesExcludingArray
+     */
+    public function testReplaceOneReplacementArgumentProhibitsUpdatePipeline($replacement): void
     {
-        return [
-            'update:array' => [['$set' => ['x' => 1]]],
-            'update:object' => [(object) ['$set' => ['x' => 1]]],
-            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
-            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
-            // TODO: Enable the following tests when implementing PHPLIB-1129
-            //'pipeline:array' => [[['$set' => ['x' => 1]]]],
-            //'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
-            //'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
-            //'empty_pipeline:array' => [[]],
-            //'empty_pipeline:Serializable' => [new BSONArray([])],
-            //'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('$operations[0]["replaceOne"][1] is an update pipeline');
+        new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
+            [BulkWrite::REPLACE_ONE => [['x' => 1], $replacement]],
+        ]);
     }
 
     /** @dataProvider provideInvalidDocumentValues */
@@ -239,6 +242,18 @@ public function testUpdateManyFilterArgumentTypeCheck($filter): void
         ]);
     }
 
+    /**
+     * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
+     * @doesNotPerformAssertions
+     */
+    public function testUpdateManyUpdateArgument($update): void
+    {
+        new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
+            [BulkWrite::UPDATE_MANY => [['x' => 1], $update]],
+        ]);
+    }
+
     public function testUpdateManyUpdateArgumentMissing(): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -258,29 +273,19 @@ public function testUpdateManyUpdateArgumentTypeCheck($update): void
         ]);
     }
 
-    /** @dataProvider provideInvalidUpdateValues */
-    public function testUpdateManyUpdateArgumentRequiresOperatorsOrPipeline($update): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideEmptyUpdatePipelines
+     */
+    public function testUpdateManyUpdateArgumentProhibitsReplacementDocumentOrEmptyPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('First key in $operations[0]["updateMany"][1] is neither an update operator nor a pipeline');
+        $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $operations[0]["updateMany"][1]');
         new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
             [BulkWrite::UPDATE_MANY => [['x' => 1], $update]],
         ]);
     }
 
-    public function provideInvalidUpdateValues(): array
-    {
-        return [
-            'replacement:array' => [['x' => 1]],
-            'replacement:object' => [(object) ['x' => 1]],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
-            'replacement:Document' => [Document::fromPHP(['x' => 1])],
-            'empty_pipeline:array' => [[]],
-            'empty_pipeline:Serializable' => [new BSONArray([])],
-            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
-    }
-
     /** @dataProvider provideInvalidArrayValues */
     public function testUpdateManyArrayFiltersOptionTypeCheck($arrayFilters): void
     {
@@ -311,6 +316,18 @@ public function testUpdateManyUpsertOptionTypeCheck($upsert): void
         ]);
     }
 
+    /**
+     * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
+     * @doesNotPerformAssertions
+     */
+    public function testUpdateOneUpdateArgument($update): void
+    {
+        new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
+            [BulkWrite::UPDATE_ONE => [['x' => 1], $update]],
+        ]);
+    }
+
     public function testUpdateOneFilterArgumentMissing(): void
     {
         $this->expectException(InvalidArgumentException::class);
@@ -349,11 +366,14 @@ public function testUpdateOneUpdateArgumentTypeCheck($update): void
         ]);
     }
 
-    /** @dataProvider provideInvalidUpdateValues */
-    public function testUpdateOneUpdateArgumentRequiresOperatorsOrPipeline($update): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideEmptyUpdatePipelines
+     */
+    public function testUpdateOneUpdateArgumentProhibitsReplacementDocumentOrEmptyPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('First key in $operations[0]["updateOne"][1] is neither an update operator nor a pipeline');
+        $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $operations[0]["updateOne"][1]');
         new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
             [BulkWrite::UPDATE_ONE => [['x' => 1], $update]],
         ]);
diff --git a/tests/Operation/CountDocumentsFunctionalTest.php b/tests/Operation/CountDocumentsFunctionalTest.php
index 21415428d..3b3aa7cc1 100644
--- a/tests/Operation/CountDocumentsFunctionalTest.php
+++ b/tests/Operation/CountDocumentsFunctionalTest.php
@@ -2,8 +2,6 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\CountDocuments;
 use MongoDB\Operation\InsertMany;
 use MongoDB\Tests\CommandObserver;
@@ -30,18 +28,6 @@ function (array $event) use ($expectedMatchStage): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expectedQuery = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expectedQuery],
-            'object' => [(object) ['x' => 1], $expectedQuery],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
-            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
-        ];
-    }
-
     public function testEmptyCollection(): void
     {
         $operation = new CountDocuments($this->getDatabaseName(), $this->getCollectionName(), []);
diff --git a/tests/Operation/CountFunctionalTest.php b/tests/Operation/CountFunctionalTest.php
index 3f44db2b7..192dd5434 100644
--- a/tests/Operation/CountFunctionalTest.php
+++ b/tests/Operation/CountFunctionalTest.php
@@ -2,8 +2,6 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Count;
 use MongoDB\Operation\CreateIndexes;
 use MongoDB\Operation\InsertMany;
@@ -31,18 +29,6 @@ function (array $event) use ($expectedQuery): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expectedQuery = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expectedQuery],
-            'object' => [(object) ['x' => 1], $expectedQuery],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
-            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
-        ];
-    }
-
     public function testDefaultReadConcernIsOmitted(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php
index 01690b090..692441ac6 100644
--- a/tests/Operation/DeleteFunctionalTest.php
+++ b/tests/Operation/DeleteFunctionalTest.php
@@ -2,14 +2,12 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
 use MongoDB\Collection;
 use MongoDB\DeleteResult;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\BadMethodCallException;
 use MongoDB\Exception\UnsupportedException;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Delete;
 use MongoDB\Tests\CommandObserver;
 use stdClass;
@@ -48,18 +46,6 @@ function (array $event) use ($expectedQuery): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expectedQuery = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expectedQuery],
-            'object' => [(object) ['x' => 1], $expectedQuery],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
-            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
-        ];
-    }
-
     public function testDeleteOne(): void
     {
         $this->createFixtures(3);
diff --git a/tests/Operation/DistinctFunctionalTest.php b/tests/Operation/DistinctFunctionalTest.php
index 8e97f48d9..53e411a0f 100644
--- a/tests/Operation/DistinctFunctionalTest.php
+++ b/tests/Operation/DistinctFunctionalTest.php
@@ -2,9 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
 use MongoDB\Driver\BulkWrite;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Distinct;
 use MongoDB\Tests\CommandObserver;
 use stdClass;
@@ -35,18 +33,6 @@ function (array $event) use ($expectedQuery): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expectedQuery = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expectedQuery],
-            'object' => [(object) ['x' => 1], $expectedQuery],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
-            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
-        ];
-    }
-
     public function testDefaultReadConcernIsOmitted(): void
     {
         (new CommandObserver())->observe(
diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php
index 86d2747f9..22b2c9e56 100644
--- a/tests/Operation/FindAndModifyFunctionalTest.php
+++ b/tests/Operation/FindAndModifyFunctionalTest.php
@@ -3,12 +3,10 @@
 namespace MongoDB\Tests\Operation;
 
 use MongoDB\BSON\Document;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\Exception\CommandException;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\UnsupportedException;
-use MongoDB\Model\BSONArray;
 use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\FindAndModify;
 use MongoDB\Tests\CommandObserver;
@@ -53,6 +51,7 @@ public function provideQueryDocuments(): array
      * @dataProvider provideReplacementDocuments
      * @dataProvider provideUpdateDocuments
      * @dataProvider provideUpdatePipelines
+     * @dataProvider provideReplacementDocumentLikePipeline
      */
     public function testUpdateDocuments($update, $expectedUpdate): void
     {
@@ -75,38 +74,16 @@ function (array $event) use ($expectedUpdate): void {
         );
     }
 
-    public function provideReplacementDocuments(): array
+    public function provideReplacementDocumentLikePipeline(): array
     {
-        $expected = (object) ['x' => 1];
-
-        return [
-            'replacement:array' => [['x' => 1], $expected],
-            'replacement:object' => [(object) ['x' => 1], $expected],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
-            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
-        ];
-    }
-
-    public function provideUpdateDocuments(): array
-    {
-        $expected = (object) ['$set' => (object) ['x' => 1]];
-
+        /* Note: this expected value differs from UpdateFunctionalTest because
+         * FindAndModify is not affected by libmongoc's pipeline detection for
+         * update commands (see: CDRIVER-4658). */
         return [
-            'update:array' => [['$set' => ['x' => 1]], $expected],
-            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
-            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
-            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
-        ];
-    }
-
-    public function provideUpdatePipelines(): array
-    {
-        $expected = [(object) ['$set' => (object) ['x' => 1]]];
-
-        return [
-            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
-            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
-            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
+            'replacement_like_pipeline' => [
+                (object) ['0' => ['$set' => ['x' => 1]]],
+                (object) ['0' => (object) ['$set' => (object) ['x' => 1]]],
+            ],
         ];
     }
 
diff --git a/tests/Operation/FindFunctionalTest.php b/tests/Operation/FindFunctionalTest.php
index a4238e0e5..a7975f338 100644
--- a/tests/Operation/FindFunctionalTest.php
+++ b/tests/Operation/FindFunctionalTest.php
@@ -34,18 +34,6 @@ function (array $event) use ($expectedQuery): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expectedQuery = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expectedQuery],
-            'object' => [(object) ['x' => 1], $expectedQuery],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expectedQuery],
-            'Document' => [Document::fromPHP(['x' => 1]), $expectedQuery],
-        ];
-    }
-
     /** @dataProvider provideModifierDocuments */
     public function testModifierDocuments($modifiers, stdClass $expectedSort): void
     {
diff --git a/tests/Operation/FindOneAndReplaceTest.php b/tests/Operation/FindOneAndReplaceTest.php
index c50777055..b084036f4 100644
--- a/tests/Operation/FindOneAndReplaceTest.php
+++ b/tests/Operation/FindOneAndReplaceTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-//use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-//use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\FindOneAndReplace;
 
 class FindOneAndReplaceTest extends TestCase
@@ -25,29 +21,32 @@ public function testConstructorReplacementArgumentTypeCheck($replacement): void
         new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement);
     }
 
-    /** @dataProvider provideInvalidReplacementValues */
-    public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @doesNotPerformAssertions
+     */
+    public function testConstructorReplacementArgument($replacement): void
+    {
+        new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement);
+    }
+
+    /** @dataProvider provideUpdateDocuments */
+    public function testConstructorReplacementArgumentProhibitsUpdateDocument($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('First key in $replacement argument is an update operator');
+        $this->expectExceptionMessage('First key in $replacement is an update operator');
         new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement);
     }
 
-    public function provideInvalidReplacementValues(): array
+    /**
+     * @dataProvider provideUpdatePipelines
+     * @dataProvider provideEmptyUpdatePipelinesExcludingArray
+     */
+    public function testConstructorReplacementArgumentProhibitsUpdatePipeline($replacement): void
     {
-        return [
-            'update:array' => [['$set' => ['x' => 1]]],
-            'update:object' => [(object) ['$set' => ['x' => 1]]],
-            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
-            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
-            // TODO: Enable the following tests when implementing PHPLIB-1129
-            //'pipeline:array' => [[['$set' => ['x' => 1]]]],
-            //'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
-            //'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
-            //'empty_pipeline:array' => [[]],
-            //'empty_pipeline:Serializable' => [new BSONArray([])],
-            //'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('$replacement is an update pipeline');
+        new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), [], $replacement);
     }
 
     /** @dataProvider provideInvalidConstructorOptions */
diff --git a/tests/Operation/FindOneAndUpdateTest.php b/tests/Operation/FindOneAndUpdateTest.php
index 2b57b7f5b..8514cea86 100644
--- a/tests/Operation/FindOneAndUpdateTest.php
+++ b/tests/Operation/FindOneAndUpdateTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\FindOneAndUpdate;
 
 class FindOneAndUpdateTest extends TestCase
@@ -25,27 +21,17 @@ public function testConstructorUpdateArgumentTypeCheck($update): void
         new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], $update);
     }
 
-    /** @dataProvider provideInvalidUpdateValues */
-    public function testConstructorUpdateArgumentRequiresOperatorsOrPipeline($update): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideEmptyUpdatePipelines
+     */
+    public function testConstructorUpdateArgumentProhibitsReplacementDocumentOrEmptyPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
+        $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $update');
         new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), [], $update);
     }
 
-    public function provideInvalidUpdateValues(): array
-    {
-        return [
-            'replacement:array' => [['x' => 1]],
-            'replacement:object' => [(object) ['x' => 1]],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
-            'replacement:Document' => [Document::fromPHP(['x' => 1])],
-            'empty_pipeline:array' => [[]],
-            'empty_pipeline:Serializable' => [new BSONArray([])],
-            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
-    }
-
     /** @dataProvider provideInvalidConstructorOptions */
     public function testConstructorOptionTypeChecks(array $options): void
     {
diff --git a/tests/Operation/FunctionalTestCase.php b/tests/Operation/FunctionalTestCase.php
index 3da36fd71..c07a35712 100644
--- a/tests/Operation/FunctionalTestCase.php
+++ b/tests/Operation/FunctionalTestCase.php
@@ -2,8 +2,12 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
 use MongoDB\Driver\ReadConcern;
 use MongoDB\Driver\WriteConcern;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Tests\FunctionalTestCase as BaseFunctionalTestCase;
 
 /**
@@ -18,6 +22,64 @@ public function setUp(): void
         $this->dropCollection($this->getDatabaseName(), $this->getCollectionName());
     }
 
+    public function provideFilterDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+
+        return [
+            'filter:array' => [['x' => 1], $expected],
+            'filter:object' => [(object) ['x' => 1], $expected],
+            'filter:Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'filter:Document' => [Document::fromPHP(['x' => 1]), $expected],
+        ];
+    }
+
+    public function provideReplacementDocuments(): array
+    {
+        $expected = (object) ['x' => 1];
+        $expectedEmpty = (object) [];
+
+        return [
+            'replacement:array' => [['x' => 1], $expected],
+            'replacement:object' => [(object) ['x' => 1], $expected],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
+            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
+            /* Note: empty arrays could also express an empty pipeline, but we
+             * should interpret them as an empty replacement document for BC. */
+            'empty_replacement:array' => [[], $expectedEmpty],
+            'empty_replacement:object' => [(object) [], $expectedEmpty],
+            'empty_replacement:Serializable' => [new BSONDocument([]), $expectedEmpty],
+            'empty_replacement:Document' => [Document::fromPHP([]), $expectedEmpty],
+        ];
+    }
+
+    public function provideUpdateDocuments(): array
+    {
+        $expected = (object) ['$set' => (object) ['x' => 1]];
+
+        return [
+            'update:array' => [['$set' => ['x' => 1]], $expected],
+            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
+        ];
+    }
+
+    public function provideUpdatePipelines(): array
+    {
+        $expected = [(object) ['$set' => (object) ['x' => 1]]];
+
+        return [
+            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
+            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
+            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
+            /* Note: although empty pipelines are valid NOPs for update and
+             * findAndModify commands, they are not supported for updates in
+             * libmongoc since they are indistinguishable from empty replacement
+             * documents (both are empty bson_t structs). */
+        ];
+    }
+
     protected function createDefaultReadConcern()
     {
         return new ReadConcern();
diff --git a/tests/Operation/ReplaceOneTest.php b/tests/Operation/ReplaceOneTest.php
index 2b4446fc1..fd057921e 100644
--- a/tests/Operation/ReplaceOneTest.php
+++ b/tests/Operation/ReplaceOneTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-//use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-//use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\ReplaceOne;
 
 class ReplaceOneTest extends TestCase
@@ -34,37 +30,22 @@ public function testConstructorReplacementArgument($replacement): void
         new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
     }
 
-    public function provideReplacementDocuments()
-    {
-        return $this->wrapValuesForDataProvider([
-            ['y' => 1],
-            (object) ['y' => 1],
-            new BSONDocument(['y' => 1]),
-        ]);
-    }
-
-    /** @dataProvider provideInvalidReplacementValues */
-    public function testConstructorReplacementArgumentRequiresNoOperators($replacement): void
+    /** @dataProvider provideUpdateDocuments */
+    public function testConstructorReplacementArgumentProhibitsUpdateDocument($replacement): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('First key in $replacement argument is an update operator');
+        $this->expectExceptionMessage('First key in $replacement is an update operator');
         new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
     }
 
-    public function provideInvalidReplacementValues(): array
+    /**
+     * @dataProvider provideUpdatePipelines
+     * @dataProvider provideEmptyUpdatePipelinesExcludingArray
+     */
+    public function testConstructorReplacementArgumentProhibitsUpdatePipeline($replacement): void
     {
-        return [
-            'update:array' => [['$set' => ['x' => 1]]],
-            'update:object' => [(object) ['$set' => ['x' => 1]]],
-            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
-            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
-            // TODO: Enable the following tests when implementing PHPLIB-1129
-            //'pipeline:array' => [[['$set' => ['x' => 1]]]],
-            //'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
-            //'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
-            //'empty_pipeline:array' => [[]],
-            //'empty_pipeline:Serializable' => [new BSONArray([])],
-            //'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
+        $this->expectException(InvalidArgumentException::class);
+        $this->expectExceptionMessage('$replacement is an update pipeline');
+        new ReplaceOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $replacement);
     }
 }
diff --git a/tests/Operation/TestCase.php b/tests/Operation/TestCase.php
index 2de8b0e68..684899ec5 100644
--- a/tests/Operation/TestCase.php
+++ b/tests/Operation/TestCase.php
@@ -2,6 +2,10 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\BSON\Document;
+use MongoDB\BSON\PackedArray;
+use MongoDB\Model\BSONArray;
+use MongoDB\Model\BSONDocument;
 use MongoDB\Tests\TestCase as BaseTestCase;
 
 /**
@@ -9,4 +13,65 @@
  */
 abstract class TestCase extends BaseTestCase
 {
+    public function provideReplacementDocuments(): array
+    {
+        return [
+            'replacement:array' => [['x' => 1]],
+            'replacement:object' => [(object) ['x' => 1]],
+            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
+            'replacement:Document' => [Document::fromPHP(['x' => 1])],
+            /* Note: empty arrays could also express a pipeline, but PHPLIB
+             * interprets them as a replacement document for BC. */
+            'empty_replacement:array' => [[]],
+            'empty_replacement:object' => [(object) []],
+            'empty_replacement:Serializable' => [new BSONDocument([])],
+            'empty_replacement:Document' => [Document::fromPHP([])],
+        ];
+    }
+
+    public function provideUpdateDocuments(): array
+    {
+        return [
+            'update:array' => [['$set' => ['x' => 1]]],
+            'update:object' => [(object) ['$set' => ['x' => 1]]],
+            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]])],
+            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]])],
+        ];
+    }
+
+    public function provideUpdatePipelines(): array
+    {
+        return [
+            'pipeline:array' => [[['$set' => ['x' => 1]]]],
+            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]])],
+            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]])],
+        ];
+    }
+
+    public function provideEmptyUpdatePipelines(): array
+    {
+        /* Empty update pipelines are accepted by the update and findAndModify
+         * commands (as NOPs); however, they are not supported for updates in
+         * libmongoc because empty arrays and documents have the same bson_t
+         * representation (libmongoc considers it an empty replacement for BC).
+         * For consistency, PHPLIB rejects empty pipelines for updateOne,
+         * updateMany, and findOneAndUpdate operations. Replace operations
+         * interpret empty arrays as replacement documents for BC, but rejects
+         * other representations. */
+        return [
+            'empty_pipeline:array' => [[]],
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
+
+    public function provideEmptyUpdatePipelinesExcludingArray(): array
+    {
+        /* This data provider is used for replace operations, which accept empty
+         * arrays as replacement documents for BC. */
+        return [
+            'empty_pipeline:Serializable' => [new BSONArray([])],
+            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
+        ];
+    }
 }
diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php
index e6a24217e..7af2fc674 100644
--- a/tests/Operation/UpdateFunctionalTest.php
+++ b/tests/Operation/UpdateFunctionalTest.php
@@ -2,16 +2,12 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
 use MongoDB\BSON\ObjectId;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Collection;
 use MongoDB\Driver\BulkWrite;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\BadMethodCallException;
 use MongoDB\Exception\UnsupportedException;
-use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Update;
 use MongoDB\Tests\CommandObserver;
 use MongoDB\UpdateResult;
@@ -52,22 +48,11 @@ function (array $event) use ($expectedFilter): void {
         );
     }
 
-    public function provideFilterDocuments(): array
-    {
-        $expected = (object) ['x' => 1];
-
-        return [
-            'array' => [['x' => 1], $expected],
-            'object' => [(object) ['x' => 1], $expected],
-            'Serializable' => [new BSONDocument(['x' => 1]), $expected],
-            'Document' => [Document::fromPHP(['x' => 1]), $expected],
-        ];
-    }
-
     /**
      * @dataProvider provideReplacementDocuments
      * @dataProvider provideUpdateDocuments
      * @dataProvider provideUpdatePipelines
+     * @dataProvider provideReplacementDocumentLikePipeline
      */
     public function testUpdateDocuments($update, $expectedUpdate): void
     {
@@ -92,38 +77,15 @@ function (array $event) use ($expectedUpdate): void {
         );
     }
 
-    public function provideReplacementDocuments(): array
+    public function provideReplacementDocumentLikePipeline(): array
     {
-        $expected = (object) ['x' => 1];
-
-        return [
-            'replacement:array' => [['x' => 1], $expected],
-            'replacement:object' => [(object) ['x' => 1], $expected],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1]), $expected],
-            'replacement:Document' => [Document::fromPHP(['x' => 1]), $expected],
-        ];
-    }
-
-    public function provideUpdateDocuments(): array
-    {
-        $expected = (object) ['$set' => (object) ['x' => 1]];
-
-        return [
-            'update:array' => [['$set' => ['x' => 1]], $expected],
-            'update:object' => [(object) ['$set' => ['x' => 1]], $expected],
-            'update:Serializable' => [new BSONDocument(['$set' => ['x' => 1]]), $expected],
-            'update:Document' => [Document::fromPHP(['$set' => ['x' => 1]]), $expected],
-        ];
-    }
-
-    public function provideUpdatePipelines(): array
-    {
-        $expected = [(object) ['$set' => (object) ['x' => 1]]];
-
+        /* Note: libmongoc encodes this replacement document as a BSON array
+         * because it resembles an update pipeline (see: CDRIVER-4658). */
         return [
-            'pipeline:array' => [[['$set' => ['x' => 1]]], $expected],
-            'pipeline:Serializable' => [new BSONArray([['$set' => ['x' => 1]]]), $expected],
-            'pipeline:PackedArray' => [PackedArray::fromPHP([['$set' => ['x' => 1]]]), $expected],
+            'replacement_like_pipeline' => [
+                (object) ['0' => ['$set' => ['x' => 1]]],
+                [(object) ['$set' => (object) ['x' => 1]]],
+            ],
         ];
     }
 
diff --git a/tests/Operation/UpdateManyTest.php b/tests/Operation/UpdateManyTest.php
index 02b2c1ae1..7f12207c8 100644
--- a/tests/Operation/UpdateManyTest.php
+++ b/tests/Operation/UpdateManyTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\UpdateMany;
 
 class UpdateManyTest extends TestCase
@@ -27,6 +23,7 @@ public function testConstructorUpdateArgumentTypeCheck($update): void
 
     /**
      * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
      * @doesNotPerformAssertions
      */
     public function testConstructorUpdateArgument($update): void
@@ -34,33 +31,14 @@ public function testConstructorUpdateArgument($update): void
         new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    public function provideUpdateDocuments()
-    {
-        return $this->wrapValuesForDataProvider([
-            ['$set' => ['y' => 1]],
-            (object) ['$set' => ['y' => 1]],
-            new BSONDocument(['$set' => ['y' => 1]]),
-        ]);
-    }
-
-    /** @dataProvider provideInvalidUpdateValues */
-    public function testConstructorUpdateArgumentRequiresOperators($update): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideEmptyUpdatePipelines
+     */
+    public function testConstructorUpdateArgumentProhibitsReplacementDocumentOrEmptyPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
+        $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $update');
         new UpdateMany($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
-
-    public function provideInvalidUpdateValues(): array
-    {
-        return [
-            'replacement:array' => [['x' => 1]],
-            'replacement:object' => [(object) ['x' => 1]],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
-            'replacement:Document' => [Document::fromPHP(['x' => 1])],
-            'empty_pipeline:array' => [[]],
-            'empty_pipeline:Serializable' => [new BSONArray([])],
-            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
-    }
 }
diff --git a/tests/Operation/UpdateOneTest.php b/tests/Operation/UpdateOneTest.php
index fa44e7d06..657f3d650 100644
--- a/tests/Operation/UpdateOneTest.php
+++ b/tests/Operation/UpdateOneTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\UpdateOne;
 
 class UpdateOneTest extends TestCase
@@ -27,6 +23,7 @@ public function testConstructorUpdateArgumentTypeCheck($update): void
 
     /**
      * @dataProvider provideUpdateDocuments
+     * @dataProvider provideUpdatePipelines
      * @doesNotPerformAssertions
      */
     public function testConstructorUpdateArgument($update): void
@@ -34,33 +31,14 @@ public function testConstructorUpdateArgument($update): void
         new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
 
-    public function provideUpdateDocuments()
-    {
-        return $this->wrapValuesForDataProvider([
-            ['$set' => ['y' => 1]],
-            (object) ['$set' => ['y' => 1]],
-            new BSONDocument(['$set' => ['y' => 1]]),
-        ]);
-    }
-
-    /** @dataProvider provideInvalidUpdateValues */
-    public function testConstructorUpdateArgumentRequiresOperators($update): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideEmptyUpdatePipelines
+     */
+    public function testConstructorUpdateArgumentProhibitsReplacementDocumentOrEmptyPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('Expected an update document with operator as first key or a pipeline');
+        $this->expectExceptionMessage('Expected update operator(s) or non-empty pipeline for $update');
         new UpdateOne($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update);
     }
-
-    public function provideInvalidUpdateValues(): array
-    {
-        return [
-            'replacement:array' => [['x' => 1]],
-            'replacement:object' => [(object) ['x' => 1]],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
-            'replacement:Document' => [Document::fromPHP(['x' => 1])],
-            'empty_pipeline:array' => [[]],
-            'empty_pipeline:Serializable' => [new BSONArray([])],
-            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
-    }
 }
diff --git a/tests/Operation/UpdateTest.php b/tests/Operation/UpdateTest.php
index 40dce6238..bcc445544 100644
--- a/tests/Operation/UpdateTest.php
+++ b/tests/Operation/UpdateTest.php
@@ -2,11 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
-use MongoDB\BSON\Document;
-use MongoDB\BSON\PackedArray;
 use MongoDB\Exception\InvalidArgumentException;
-use MongoDB\Model\BSONArray;
-use MongoDB\Model\BSONDocument;
 use MongoDB\Operation\Update;
 
 class UpdateTest extends TestCase
@@ -69,24 +65,14 @@ public function provideInvalidConstructorOptions()
         return $options;
     }
 
-    /** @dataProvider provideInvalidUpdateValues */
-    public function testConstructorMultiOptionRequiresOperators($update): void
+    /**
+     * @dataProvider provideReplacementDocuments
+     * @dataProvider provideEmptyUpdatePipelines
+     */
+    public function testConstructorMultiOptionProhibitsReplacementDocumentOrEmptyPipeline($update): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('"multi" option cannot be true if $update is a replacement document');
+        $this->expectExceptionMessage('"multi" option cannot be true unless $update has update operator(s) or non-empty pipeline');
         new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update, ['multi' => true]);
     }
-
-    public function provideInvalidUpdateValues(): array
-    {
-        return [
-            'replacement:array' => [['x' => 1]],
-            'replacement:object' => [(object) ['x' => 1]],
-            'replacement:Serializable' => [new BSONDocument(['x' => 1])],
-            'replacement:Document' => [Document::fromPHP(['x' => 1])],
-            'empty_pipeline:array' => [[]],
-            'empty_pipeline:Serializable' => [new BSONArray([])],
-            'empty_pipeline:PackedArray' => [PackedArray::fromPHP([])],
-        ];
-    }
 }

From c0738eb2de28955f3be9ff983158c1f0cdeda825 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Mon, 12 Jun 2023 10:24:03 +0200
Subject: [PATCH 303/321] PHPLIB-1152: replace `private static` with `private
 const` (#1099)

Exception Client::$version which is initialized dynamically

Co-authored-by: Jeremy Mikola 
---
 psalm-baseline.xml                          |  5 ++++
 src/ChangeStream.php                        | 17 +++++-------
 src/Client.php                              | 12 ++++-----
 src/Collection.php                          | 10 +++----
 src/Database.php                            | 10 +++----
 src/GridFS/Bucket.php                       | 30 +++++++++------------
 src/GridFS/WritableStream.php               |  5 ++--
 src/Model/BSONIterator.php                  |  9 +++----
 src/Operation/CreateEncryptedCollection.php |  5 ++--
 src/Operation/CreateIndexes.php             |  5 ++--
 src/Operation/Delete.php                    |  5 ++--
 src/Operation/DropCollection.php            |  5 ++--
 src/Operation/Explain.php                   |  5 ++--
 src/Operation/FindAndModify.php             | 10 +++----
 src/Operation/ListIndexes.php               |  9 +++----
 src/Operation/Update.php                    |  5 ++--
 src/Operation/Watch.php                     |  5 ++--
 17 files changed, 64 insertions(+), 88 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index ead3a341c..b8640c4f2 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -9,6 +9,11 @@
       $type
     
   
+  
+    
+      self::CURSOR_NOT_FOUND
+    
+  
   
     
       $driverOptions['driver'] ?? []
diff --git a/src/ChangeStream.php b/src/ChangeStream.php
index 628a9886c..91282e8fa 100644
--- a/src/ChangeStream.php
+++ b/src/ChangeStream.php
@@ -42,15 +42,11 @@ class ChangeStream implements Iterator
 {
     /**
      * @deprecated 1.4
-     * @todo Remove this in 2.0 (see: PHPLIB-360)
+     * @todo make this constant private in 2.0 (see: PHPLIB-360)
      */
     public const CURSOR_NOT_FOUND = 43;
 
-    /** @var int */
-    private static $cursorNotFound = 43;
-
-    /** @var int[] */
-    private static $resumableErrorCodes = [
+    private const RESUMABLE_ERROR_CODES = [
         6, // HostUnreachable
         7, // HostNotFound
         89, // NetworkTimeout
@@ -70,8 +66,7 @@ class ChangeStream implements Iterator
         133, // FailedToSatisfyReadPreference
     ];
 
-    /** @var int */
-    private static $wireVersionForResumableChangeStreamError = 9;
+    private const WIRE_VERSION_FOR_RESUMABLE_CHANGE_STREAM_ERROR = 9;
 
     /** @var ResumeCallable|null */
     private $resumeCallable;
@@ -205,15 +200,15 @@ private function isResumableError(RuntimeException $exception): bool
             return false;
         }
 
-        if ($exception->getCode() === self::$cursorNotFound) {
+        if ($exception->getCode() === self::CURSOR_NOT_FOUND) {
             return true;
         }
 
-        if (server_supports_feature($this->iterator->getServer(), self::$wireVersionForResumableChangeStreamError)) {
+        if (server_supports_feature($this->iterator->getServer(), self::WIRE_VERSION_FOR_RESUMABLE_CHANGE_STREAM_ERROR)) {
             return $exception->hasErrorLabel('ResumableChangeStreamError');
         }
 
-        return in_array($exception->getCode(), self::$resumableErrorCodes);
+        return in_array($exception->getCode(), self::RESUMABLE_ERROR_CODES);
     }
 
     /**
diff --git a/src/Client.php b/src/Client.php
index bb12c3776..93ff71f6b 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -46,15 +46,13 @@ class Client
 {
     public const DEFAULT_URI = 'mongodb://127.0.0.1/';
 
-    /** @var array */
-    private static $defaultTypeMap = [
+    private const DEFAULT_TYPE_MAP = [
         'array' => BSONArray::class,
         'document' => BSONDocument::class,
         'root' => BSONDocument::class,
     ];
 
-    /** @var string */
-    private static $handshakeSeparator = ' / ';
+    private const HANDSHAKE_SEPARATOR = '/';
 
     /** @var string|null */
     private static $version;
@@ -102,7 +100,7 @@ class Client
      */
     public function __construct(?string $uri = null, array $uriOptions = [], array $driverOptions = [])
     {
-        $driverOptions += ['typeMap' => self::$defaultTypeMap];
+        $driverOptions += ['typeMap' => self::DEFAULT_TYPE_MAP];
 
         if (! is_array($driverOptions['typeMap'])) {
             throw InvalidArgumentException::invalidType('"typeMap" driver option', $driverOptions['typeMap'], 'array');
@@ -405,7 +403,7 @@ private function mergeDriverInfo(array $driver): array
                 throw InvalidArgumentException::invalidType('"name" handshake option', $driver['name'], 'string');
             }
 
-            $mergedDriver['name'] .= self::$handshakeSeparator . $driver['name'];
+            $mergedDriver['name'] .= self::HANDSHAKE_SEPARATOR . $driver['name'];
         }
 
         if (isset($driver['version'])) {
@@ -413,7 +411,7 @@ private function mergeDriverInfo(array $driver): array
                 throw InvalidArgumentException::invalidType('"version" handshake option', $driver['version'], 'string');
             }
 
-            $mergedDriver['version'] .= self::$handshakeSeparator . $driver['version'];
+            $mergedDriver['version'] .= self::HANDSHAKE_SEPARATOR . $driver['version'];
         }
 
         if (isset($driver['platform'])) {
diff --git a/src/Collection.php b/src/Collection.php
index c6d0e30ec..61e020db5 100644
--- a/src/Collection.php
+++ b/src/Collection.php
@@ -69,15 +69,13 @@
 
 class Collection
 {
-    /** @var array */
-    private static $defaultTypeMap = [
+    private const DEFAULT_TYPE_MAP = [
         'array' => BSONArray::class,
         'document' => BSONDocument::class,
         'root' => BSONDocument::class,
     ];
 
-    /** @var integer */
-    private static $wireVersionForReadConcernWithWriteStage = 8;
+    private const WIRE_VERSION_FOR_READ_CONCERN_WITH_WRITE_STAGE = 8;
 
     /** @var string */
     private $collectionName;
@@ -158,7 +156,7 @@ public function __construct(Manager $manager, string $databaseName, string $coll
         $this->collectionName = $collectionName;
         $this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
         $this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
-        $this->typeMap = $options['typeMap'] ?? self::$defaultTypeMap;
+        $this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
         $this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
     }
 
@@ -229,7 +227,7 @@ public function aggregate(array $pipeline, array $options = [])
         if (
             ! isset($options['readConcern']) &&
             ! is_in_transaction($options) &&
-            ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage))
+            ( ! $hasWriteStage || server_supports_feature($server, self::WIRE_VERSION_FOR_READ_CONCERN_WITH_WRITE_STAGE))
         ) {
             $options['readConcern'] = $this->readConcern;
         }
diff --git a/src/Database.php b/src/Database.php
index 5eea326b2..9c09969b6 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -53,15 +53,13 @@
 
 class Database
 {
-    /** @var array */
-    private static $defaultTypeMap = [
+    private const DEFAULT_TYPE_MAP = [
         'array' => BSONArray::class,
         'document' => BSONDocument::class,
         'root' => BSONDocument::class,
     ];
 
-    /** @var integer */
-    private static $wireVersionForReadConcernWithWriteStage = 8;
+    private const WIRE_VERSION_FOR_READ_CONCERN_WITH_WRITE_STAGE = 8;
 
     /** @var string */
     private $databaseName;
@@ -134,7 +132,7 @@ public function __construct(Manager $manager, string $databaseName, array $optio
         $this->databaseName = $databaseName;
         $this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
         $this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
-        $this->typeMap = $options['typeMap'] ?? self::$defaultTypeMap;
+        $this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
         $this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
     }
 
@@ -217,7 +215,7 @@ public function aggregate(array $pipeline, array $options = [])
         if (
             ! isset($options['readConcern']) &&
             ! is_in_transaction($options) &&
-            ( ! $hasWriteStage || server_supports_feature($server, self::$wireVersionForReadConcernWithWriteStage))
+            ( ! $hasWriteStage || server_supports_feature($server, self::WIRE_VERSION_FOR_READ_CONCERN_WITH_WRITE_STAGE))
         ) {
             $options['readConcern'] = $this->readConcern;
         }
diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php
index a9acf8a52..3dba068e8 100644
--- a/src/GridFS/Bucket.php
+++ b/src/GridFS/Bucket.php
@@ -62,21 +62,17 @@
  */
 class Bucket
 {
-    /** @var string */
-    private static $defaultBucketName = 'fs';
+    private const DEFAULT_BUCKET_NAME = 'fs';
 
-    /** @var integer */
-    private static $defaultChunkSizeBytes = 261120;
+    private const DEFAULT_CHUNK_SIZE_BYTES = 261120;
 
-    /** @var array */
-    private static $defaultTypeMap = [
+    private const DEFAULT_TYPE_MAP = [
         'array' => BSONArray::class,
         'document' => BSONDocument::class,
         'root' => BSONDocument::class,
     ];
 
-    /** @var string */
-    private static $streamWrapperProtocol = 'gridfs';
+    private const STREAM_WRAPPER_PROTOCOL = 'gridfs';
 
     /** @var CollectionWrapper */
     private $collectionWrapper;
@@ -138,8 +134,8 @@ class Bucket
     public function __construct(Manager $manager, string $databaseName, array $options = [])
     {
         $options += [
-            'bucketName' => self::$defaultBucketName,
-            'chunkSizeBytes' => self::$defaultChunkSizeBytes,
+            'bucketName' => self::DEFAULT_BUCKET_NAME,
+            'chunkSizeBytes' => self::DEFAULT_CHUNK_SIZE_BYTES,
             'disableMD5' => false,
         ];
 
@@ -182,7 +178,7 @@ public function __construct(Manager $manager, string $databaseName, array $optio
         $this->disableMD5 = $options['disableMD5'];
         $this->readConcern = $options['readConcern'] ?? $this->manager->getReadConcern();
         $this->readPreference = $options['readPreference'] ?? $this->manager->getReadPreference();
-        $this->typeMap = $options['typeMap'] ?? self::$defaultTypeMap;
+        $this->typeMap = $options['typeMap'] ?? self::DEFAULT_TYPE_MAP;
         $this->writeConcern = $options['writeConcern'] ?? $this->manager->getWriteConcern();
 
         $collectionOptions = array_intersect_key($options, ['readConcern' => 1, 'readPreference' => 1, 'typeMap' => 1, 'writeConcern' => 1]);
@@ -555,7 +551,7 @@ public function openUploadStream(string $filename, array $options = [])
 
         $path = $this->createPathForUpload();
         $context = stream_context_create([
-            self::$streamWrapperProtocol => [
+            self::STREAM_WRAPPER_PROTOCOL => [
                 'collectionWrapper' => $this->collectionWrapper,
                 'filename' => $filename,
                 'options' => $options,
@@ -651,7 +647,7 @@ private function createPathForFile(object $file): string
 
         return sprintf(
             '%s://%s/%s.files/%s',
-            self::$streamWrapperProtocol,
+            self::STREAM_WRAPPER_PROTOCOL,
             urlencode($this->databaseName),
             urlencode($this->bucketName),
             urlencode($id)
@@ -665,7 +661,7 @@ private function createPathForUpload(): string
     {
         return sprintf(
             '%s://%s/%s.files',
-            self::$streamWrapperProtocol,
+            self::STREAM_WRAPPER_PROTOCOL,
             urlencode($this->databaseName),
             urlencode($this->bucketName)
         );
@@ -713,7 +709,7 @@ private function openDownloadStreamByFile(object $file)
     {
         $path = $this->createPathForFile($file);
         $context = stream_context_create([
-            self::$streamWrapperProtocol => [
+            self::STREAM_WRAPPER_PROTOCOL => [
                 'collectionWrapper' => $this->collectionWrapper,
                 'file' => $file,
             ],
@@ -727,10 +723,10 @@ private function openDownloadStreamByFile(object $file)
      */
     private function registerStreamWrapper(): void
     {
-        if (in_array(self::$streamWrapperProtocol, stream_get_wrappers())) {
+        if (in_array(self::STREAM_WRAPPER_PROTOCOL, stream_get_wrappers())) {
             return;
         }
 
-        StreamWrapper::register(self::$streamWrapperProtocol);
+        StreamWrapper::register(self::STREAM_WRAPPER_PROTOCOL);
     }
 }
diff --git a/src/GridFS/WritableStream.php b/src/GridFS/WritableStream.php
index dd2963fda..2228244d5 100644
--- a/src/GridFS/WritableStream.php
+++ b/src/GridFS/WritableStream.php
@@ -45,8 +45,7 @@
  */
 class WritableStream
 {
-    /** @var integer */
-    private static $defaultChunkSizeBytes = 261120;
+    private const DEFAULT_CHUNK_SIZE_BYTES = 261120;
 
     /** @var string */
     private $buffer = '';
@@ -107,7 +106,7 @@ public function __construct(CollectionWrapper $collectionWrapper, string $filena
     {
         $options += [
             '_id' => new ObjectId(),
-            'chunkSizeBytes' => self::$defaultChunkSizeBytes,
+            'chunkSizeBytes' => self::DEFAULT_CHUNK_SIZE_BYTES,
             'disableMD5' => false,
         ];
 
diff --git a/src/Model/BSONIterator.php b/src/Model/BSONIterator.php
index 25d9b613d..daf1d413e 100644
--- a/src/Model/BSONIterator.php
+++ b/src/Model/BSONIterator.php
@@ -34,8 +34,7 @@
  */
 class BSONIterator implements Iterator
 {
-    /** @var integer */
-    private static $bsonSize = 4;
+    private const BSON_SIZE = 4;
 
     /** @var string */
     private $buffer;
@@ -141,11 +140,11 @@ private function advance(): void
             return;
         }
 
-        if ($this->bufferLength - $this->position < self::$bsonSize) {
-            throw new UnexpectedValueException(sprintf('Expected at least %d bytes; %d remaining', self::$bsonSize, $this->bufferLength - $this->position));
+        if ($this->bufferLength - $this->position < self::BSON_SIZE) {
+            throw new UnexpectedValueException(sprintf('Expected at least %d bytes; %d remaining', self::BSON_SIZE, $this->bufferLength - $this->position));
         }
 
-        [, $documentLength] = unpack('V', substr($this->buffer, $this->position, self::$bsonSize));
+        [, $documentLength] = unpack('V', substr($this->buffer, $this->position, self::BSON_SIZE));
 
         if ($this->bufferLength - $this->position < $documentLength) {
             throw new UnexpectedValueException(sprintf('Expected %d bytes; %d remaining', $documentLength, $this->bufferLength - $this->position));
diff --git a/src/Operation/CreateEncryptedCollection.php b/src/Operation/CreateEncryptedCollection.php
index 2cfc6503d..bc08b321b 100644
--- a/src/Operation/CreateEncryptedCollection.php
+++ b/src/Operation/CreateEncryptedCollection.php
@@ -49,8 +49,7 @@
  */
 class CreateEncryptedCollection implements Executable
 {
-    /** @var integer */
-    private static $wireVersionForQueryableEncryptionV2 = 21;
+    private const WIRE_VERSION_FOR_QUERYABLE_ENCRYPTION_V2 = 21;
 
     /** @var CreateCollection */
     private $createCollection;
@@ -177,7 +176,7 @@ public function createDataKeys(ClientEncryption $clientEncryption, string $kmsPr
      */
     public function execute(Server $server)
     {
-        if (! server_supports_feature($server, self::$wireVersionForQueryableEncryptionV2)) {
+        if (! server_supports_feature($server, self::WIRE_VERSION_FOR_QUERYABLE_ENCRYPTION_V2)) {
             throw new UnsupportedException('Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption.');
         }
 
diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php
index 3346c84ed..0b3ed2728 100644
--- a/src/Operation/CreateIndexes.php
+++ b/src/Operation/CreateIndexes.php
@@ -42,8 +42,7 @@
  */
 class CreateIndexes implements Executable
 {
-    /** @var integer */
-    private static $wireVersionForCommitQuorum = 9;
+    private const WIRE_VERSION_FOR_COMMIT_QUORUM = 9;
 
     /** @var string */
     private $databaseName;
@@ -188,7 +187,7 @@ private function executeCommand(Server $server): void
         if (isset($this->options['commitQuorum'])) {
             /* Drivers MUST manually raise an error if this option is specified
              * when creating an index on a pre 4.4 server. */
-            if (! server_supports_feature($server, self::$wireVersionForCommitQuorum)) {
+            if (! server_supports_feature($server, self::WIRE_VERSION_FOR_COMMIT_QUORUM)) {
                 throw UnsupportedException::commitQuorumNotSupported();
             }
 
diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php
index 129990ac4..8083495f2 100644
--- a/src/Operation/Delete.php
+++ b/src/Operation/Delete.php
@@ -43,8 +43,7 @@
  */
 class Delete implements Executable, Explainable
 {
-    /** @var integer */
-    private static $wireVersionForHint = 9;
+    private const WIRE_VERSION_FOR_HINT = 9;
 
     /** @var string */
     private $databaseName;
@@ -152,7 +151,7 @@ public function execute(Server $server)
          * unacknowledged write concern on an unsupported server. */
         if (
             isset($this->options['writeConcern']) && ! is_write_concern_acknowledged($this->options['writeConcern']) &&
-            isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHint)
+            isset($this->options['hint']) && ! server_supports_feature($server, self::WIRE_VERSION_FOR_HINT)
         ) {
             throw UnsupportedException::hintNotSupported();
         }
diff --git a/src/Operation/DropCollection.php b/src/Operation/DropCollection.php
index 0c67c1918..38b362306 100644
--- a/src/Operation/DropCollection.php
+++ b/src/Operation/DropCollection.php
@@ -38,8 +38,7 @@
  */
 class DropCollection implements Executable
 {
-    /** @var integer */
-    private static $errorCodeNamespaceNotFound = 26;
+    private const ERROR_CODE_NAMESPACE_NOT_FOUND = 26;
 
     /** @var string */
     private $databaseName;
@@ -115,7 +114,7 @@ public function execute(Server $server)
             /* The server may return an error if the collection does not exist.
              * Check for an error code and return the command reply instead of
              * throwing. */
-            if ($e->getCode() === self::$errorCodeNamespaceNotFound) {
+            if ($e->getCode() === self::ERROR_CODE_NAMESPACE_NOT_FOUND) {
                 return $e->getResultDocument();
             }
 
diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php
index 1ab9d3816..fc7852239 100644
--- a/src/Operation/Explain.php
+++ b/src/Operation/Explain.php
@@ -42,8 +42,7 @@ class Explain implements Executable
     public const VERBOSITY_EXEC_STATS = 'executionStats';
     public const VERBOSITY_QUERY = 'queryPlanner';
 
-    /** @var integer */
-    private static $wireVersionForAggregate = 7;
+    private const WIRE_VERSION_FOR_AGGREGATE = 7;
 
     /** @var string */
     private $databaseName;
@@ -110,7 +109,7 @@ public function __construct(string $databaseName, Explainable $explainable, arra
      */
     public function execute(Server $server)
     {
-        if ($this->explainable instanceof Aggregate && ! server_supports_feature($server, self::$wireVersionForAggregate)) {
+        if ($this->explainable instanceof Aggregate && ! server_supports_feature($server, self::WIRE_VERSION_FOR_AGGREGATE)) {
             throw UnsupportedException::explainNotSupported();
         }
 
diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php
index 88f411362..42d35692f 100644
--- a/src/Operation/FindAndModify.php
+++ b/src/Operation/FindAndModify.php
@@ -49,11 +49,9 @@
  */
 class FindAndModify implements Executable, Explainable
 {
-    /** @var integer */
-    private static $wireVersionForHint = 9;
+    private const WIRE_VERSION_FOR_HINT = 9;
 
-    /** @var integer */
-    private static $wireVersionForUnsupportedOptionServerSideError = 8;
+    private const WIRE_VERSION_FOR_UNSUPPORTED_OPTION_SERVER_SIDE_ERROR = 8;
 
     /** @var string */
     private $databaseName;
@@ -227,7 +225,7 @@ public function execute(Server $server)
     {
         /* Server versions >= 4.2.0 raise errors for unsupported update options.
          * For previous versions, the CRUD spec requires a client-side error. */
-        if (isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForUnsupportedOptionServerSideError)) {
+        if (isset($this->options['hint']) && ! server_supports_feature($server, self::WIRE_VERSION_FOR_UNSUPPORTED_OPTION_SERVER_SIDE_ERROR)) {
             throw UnsupportedException::hintNotSupported();
         }
 
@@ -235,7 +233,7 @@ public function execute(Server $server)
          * unacknowledged write concern on an unsupported server. */
         if (
             isset($this->options['writeConcern']) && ! is_write_concern_acknowledged($this->options['writeConcern']) &&
-            isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHint)
+            isset($this->options['hint']) && ! server_supports_feature($server, self::WIRE_VERSION_FOR_HINT)
         ) {
             throw UnsupportedException::hintNotSupported();
         }
diff --git a/src/Operation/ListIndexes.php b/src/Operation/ListIndexes.php
index 3dca9833f..1c2e29be0 100644
--- a/src/Operation/ListIndexes.php
+++ b/src/Operation/ListIndexes.php
@@ -38,11 +38,8 @@
  */
 class ListIndexes implements Executable
 {
-    /** @var integer */
-    private static $errorCodeDatabaseNotFound = 60;
-
-    /** @var integer */
-    private static $errorCodeNamespaceNotFound = 26;
+    private const ERROR_CODE_DATABASE_NOT_FOUND = 60;
+    private const ERROR_CODE_NAMESPACE_NOT_FOUND = 26;
 
     /** @var string */
     private $databaseName;
@@ -141,7 +138,7 @@ private function executeCommand(Server $server): IndexInfoIteratorIterator
              * Check for possible error codes (see: SERVER-20463) and return an
              * empty iterator instead of throwing.
              */
-            if ($e->getCode() === self::$errorCodeNamespaceNotFound || $e->getCode() === self::$errorCodeDatabaseNotFound) {
+            if ($e->getCode() === self::ERROR_CODE_NAMESPACE_NOT_FOUND || $e->getCode() === self::ERROR_CODE_DATABASE_NOT_FOUND) {
                 return new IndexInfoIteratorIterator(new EmptyIterator());
             }
 
diff --git a/src/Operation/Update.php b/src/Operation/Update.php
index a6bd8f441..ddf09c572 100644
--- a/src/Operation/Update.php
+++ b/src/Operation/Update.php
@@ -46,8 +46,7 @@
  */
 class Update implements Executable, Explainable
 {
-    /** @var integer */
-    private static $wireVersionForHint = 8;
+    private const WIRE_VERSION_FOR_HINT = 8;
 
     /** @var string */
     private $databaseName;
@@ -196,7 +195,7 @@ public function execute(Server $server)
          * unacknowledged write concern on an unsupported server. */
         if (
             isset($this->options['writeConcern']) && ! is_write_concern_acknowledged($this->options['writeConcern']) &&
-            isset($this->options['hint']) && ! server_supports_feature($server, self::$wireVersionForHint)
+            isset($this->options['hint']) && ! server_supports_feature($server, self::WIRE_VERSION_FOR_HINT)
         ) {
             throw UnsupportedException::hintNotSupported();
         }
diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php
index 5dde8d014..db04cb3f3 100644
--- a/src/Operation/Watch.php
+++ b/src/Operation/Watch.php
@@ -67,8 +67,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
     public const FULL_DOCUMENT_BEFORE_CHANGE_WHEN_AVAILABLE = 'whenAvailable';
     public const FULL_DOCUMENT_BEFORE_CHANGE_REQUIRED = 'required';
 
-    /** @var integer */
-    private static $wireVersionForStartAtOperationTime = 7;
+    private const WIRE_VERSION_FOR_START_AT_OPERATION_TIME = 7;
 
     /** @var Aggregate */
     private $aggregate;
@@ -468,7 +467,7 @@ private function shouldCaptureOperationTime(Server $server): bool
             return false;
         }
 
-        if (! server_supports_feature($server, self::$wireVersionForStartAtOperationTime)) {
+        if (! server_supports_feature($server, self::WIRE_VERSION_FOR_START_AT_OPERATION_TIME)) {
             return false;
         }
 

From 316d6d61b6b5da5902b7846c7c26233860906c09 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Mon, 12 Jun 2023 13:18:23 +0200
Subject: [PATCH 304/321] PHPLIB-1161: Leverage array_key_first in functions
 (#1101)

---
 src/functions.php | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)

diff --git a/src/functions.php b/src/functions.php
index 95f9cc9a1..5d4e0add3 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -41,10 +41,8 @@
 use function is_array;
 use function is_object;
 use function is_string;
-use function key;
 use function MongoDB\BSON\fromPHP;
 use function MongoDB\BSON\toPHP;
-use function reset;
 use function substr;
 
 /**
@@ -319,11 +317,9 @@ function is_last_pipeline_operator_write(array $pipeline): bool
         return false;
     }
 
-    $lastOp = document_to_array($lastOp);
+    $key = array_key_first(document_to_array($lastOp));
 
-    reset($lastOp);
-
-    return key($lastOp) === '$merge' || key($lastOp) === '$out';
+    return $key === '$merge' || $key === '$out';
 }
 
 /**
@@ -341,11 +337,7 @@ function is_mapreduce_output_inline($out): bool
         return false;
     }
 
-    $out = document_to_array($out);
-
-    reset($out);
-
-    return key($out) === 'inline';
+    return array_key_first(document_to_array($out)) === 'inline';
 }
 
 /**

From 487d3e82b4149787376fe4a7646a15d28e38d0d0 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Tue, 13 Jun 2023 00:34:31 +0800
Subject: [PATCH 305/321] PHPLIB-1157: Limit omitted field assertions to
 top-level (#1094)

This reverts previous functionality added in d95e7623390b8f657755f6601859d4649612a40d.

CSFLE tests are synced to mongodb/specifications@e59a0ac6daa19e7605b0a1d2c667a67367d52edd

Also updates fle2v2-CreateCollection-OldServer.json from mongodb/specifications@9e770b54bbb6315aa82a162c42c577a5b3f8037a, which was a late change for PHPLIB-1071
---
 tests/SpecTests/FunctionalTestCase.php        |  9 ++----
 .../fle2v2-CreateCollection-OldServer.json    | 32 +++++++++++++++++++
 .../tests/fle2v2-CreateCollection.json        | 18 -----------
 3 files changed, 34 insertions(+), 25 deletions(-)

diff --git a/tests/SpecTests/FunctionalTestCase.php b/tests/SpecTests/FunctionalTestCase.php
index c4cb26787..ffab8a20a 100644
--- a/tests/SpecTests/FunctionalTestCase.php
+++ b/tests/SpecTests/FunctionalTestCase.php
@@ -16,7 +16,6 @@
 use function json_encode;
 use function MongoDB\BSON\fromJSON;
 use function MongoDB\BSON\toPHP;
-use function property_exists;
 use function sprintf;
 use function version_compare;
 
@@ -97,11 +96,12 @@ public static function assertDocumentsMatch($expectedDocument, $actualDocument,
     }
 
     /**
-     * Assert omitted fields in command documents.
+     * Assert omitted top-level fields in command documents.
      *
      * Note: this method may modify the $expected object.
      *
      * @see https://github.com/mongodb/specifications/blob/master/source/transactions/tests/README.rst#null-values
+     * @see https://github.com/mongodb/specifications/blob/09ee1ebc481f1502e3246971a9419e484d736207/source/command-monitoring/tests/README.rst#additional-values
      */
     protected static function assertCommandOmittedFields(stdClass $expected, stdClass $actual): void
     {
@@ -109,11 +109,6 @@ protected static function assertCommandOmittedFields(stdClass $expected, stdClas
             if ($value === null) {
                 static::assertObjectNotHasAttribute($key, $actual);
                 unset($expected->{$key});
-                continue;
-            }
-
-            if ($value instanceof stdClass && property_exists($actual, $key) && $actual->{$key} instanceof stdClass) {
-                static::assertCommandOmittedFields($value, $actual->{$key});
             }
         }
     }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json
index d5b04b3ea..c266aa6b8 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection-OldServer.json
@@ -55,6 +55,38 @@
           "result": {
             "errorContains": "Driver support of Queryable Encryption is incompatible with server. Upgrade server to use Queryable Encryption."
           }
+        },
+        {
+          "name": "assertCollectionNotExists",
+          "object": "testRunner",
+          "arguments": {
+            "database": "default",
+            "collection": "enxcol_.encryptedCollection.esc"
+          }
+        },
+        {
+          "name": "assertCollectionNotExists",
+          "object": "testRunner",
+          "arguments": {
+            "database": "default",
+            "collection": "enxcol_.encryptedCollection.ecc"
+          }
+        },
+        {
+          "name": "assertCollectionNotExists",
+          "object": "testRunner",
+          "arguments": {
+            "database": "default",
+            "collection": "enxcol_.encryptedCollection.ecoc"
+          }
+        },
+        {
+          "name": "assertCollectionNotExists",
+          "object": "testRunner",
+          "arguments": {
+            "database": "default",
+            "collection": "encryptedCollection"
+          }
         }
       ]
     }
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
index 819d2eec3..cc8bd1714 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
@@ -158,9 +158,6 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": null,
-                "ecocCollection": null,
-                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -343,9 +340,6 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": null,
-                "ecocCollection": null,
-                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -851,9 +845,6 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": null,
-                "ecocCollection": null,
-                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -1048,9 +1039,6 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": null,
-                "ecocCollection": null,
-                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -1367,9 +1355,6 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": null,
-                "ecocCollection": null,
-                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",
@@ -1635,9 +1620,6 @@
             "command": {
               "create": "encryptedCollection",
               "encryptedFields": {
-                "escCollection": null,
-                "ecocCollection": null,
-                "eccCollection": null,
                 "fields": [
                   {
                     "path": "firstName",

From b97cffb8963d3575457655d04d565676817c9cf3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Mon, 12 Jun 2023 21:54:53 +0200
Subject: [PATCH 306/321] PHPLIB-1162: Remove unused argument
 Explainable::getCommandDocument(Server $server) (#1102)

Not a breaking change because the interface is internal.
---
 src/Operation/Aggregate.php              | 2 +-
 src/Operation/Count.php                  | 2 +-
 src/Operation/Delete.php                 | 2 +-
 src/Operation/DeleteMany.php             | 4 ++--
 src/Operation/DeleteOne.php              | 4 ++--
 src/Operation/Distinct.php               | 2 +-
 src/Operation/EstimatedDocumentCount.php | 4 ++--
 src/Operation/Explain.php                | 6 +++---
 src/Operation/Explainable.php            | 4 +---
 src/Operation/Find.php                   | 2 +-
 src/Operation/FindAndModify.php          | 2 +-
 src/Operation/FindOne.php                | 4 ++--
 src/Operation/FindOneAndDelete.php       | 4 ++--
 src/Operation/FindOneAndReplace.php      | 4 ++--
 src/Operation/FindOneAndUpdate.php       | 4 ++--
 src/Operation/Update.php                 | 2 +-
 src/Operation/UpdateMany.php             | 4 ++--
 src/Operation/UpdateOne.php              | 4 ++--
 18 files changed, 29 insertions(+), 31 deletions(-)

diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php
index b3d01f5ed..010194dff 100644
--- a/src/Operation/Aggregate.php
+++ b/src/Operation/Aggregate.php
@@ -306,7 +306,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         $cmd = $this->createCommandDocument();
 
diff --git a/src/Operation/Count.php b/src/Operation/Count.php
index 9234825f8..175ab87a9 100644
--- a/src/Operation/Count.php
+++ b/src/Operation/Count.php
@@ -170,7 +170,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         $cmd = $this->createCommandDocument();
 
diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php
index 8083495f2..48fe99470 100644
--- a/src/Operation/Delete.php
+++ b/src/Operation/Delete.php
@@ -175,7 +175,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         return ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]];
     }
diff --git a/src/Operation/DeleteMany.php b/src/Operation/DeleteMany.php
index 3d17daeba..087a60b6d 100644
--- a/src/Operation/DeleteMany.php
+++ b/src/Operation/DeleteMany.php
@@ -91,8 +91,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->delete->getCommandDocument($server);
+        return $this->delete->getCommandDocument();
     }
 }
diff --git a/src/Operation/DeleteOne.php b/src/Operation/DeleteOne.php
index d048741ad..6c3133f34 100644
--- a/src/Operation/DeleteOne.php
+++ b/src/Operation/DeleteOne.php
@@ -91,8 +91,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->delete->getCommandDocument($server);
+        return $this->delete->getCommandDocument();
     }
 }
diff --git a/src/Operation/Distinct.php b/src/Operation/Distinct.php
index 89f3faee5..87fd7c597 100644
--- a/src/Operation/Distinct.php
+++ b/src/Operation/Distinct.php
@@ -163,7 +163,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         $cmd = $this->createCommandDocument();
 
diff --git a/src/Operation/EstimatedDocumentCount.php b/src/Operation/EstimatedDocumentCount.php
index e6fa6b02a..ca53ff029 100644
--- a/src/Operation/EstimatedDocumentCount.php
+++ b/src/Operation/EstimatedDocumentCount.php
@@ -114,9 +114,9 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->createCount()->getCommandDocument($server);
+        return $this->createCount()->getCommandDocument();
     }
 
     private function createCount(): Count
diff --git a/src/Operation/Explain.php b/src/Operation/Explain.php
index fc7852239..7e3bebda6 100644
--- a/src/Operation/Explain.php
+++ b/src/Operation/Explain.php
@@ -113,7 +113,7 @@ public function execute(Server $server)
             throw UnsupportedException::explainNotSupported();
         }
 
-        $cursor = $server->executeCommand($this->databaseName, $this->createCommand($server), $this->createOptions());
+        $cursor = $server->executeCommand($this->databaseName, $this->createCommand(), $this->createOptions());
 
         if (isset($this->options['typeMap'])) {
             $cursor->setTypeMap($this->options['typeMap']);
@@ -125,9 +125,9 @@ public function execute(Server $server)
     /**
      * Create the explain command.
      */
-    private function createCommand(Server $server): Command
+    private function createCommand(): Command
     {
-        $cmd = ['explain' => $this->explainable->getCommandDocument($server)];
+        $cmd = ['explain' => $this->explainable->getCommandDocument()];
 
         foreach (['comment', 'verbosity'] as $option) {
             if (isset($this->options[$option])) {
diff --git a/src/Operation/Explainable.php b/src/Operation/Explainable.php
index 7647b51ec..f380e1c32 100644
--- a/src/Operation/Explainable.php
+++ b/src/Operation/Explainable.php
@@ -17,8 +17,6 @@
 
 namespace MongoDB\Operation;
 
-use MongoDB\Driver\Server;
-
 /**
  * Explainable interface for explainable operations (aggregate, count, distinct,
  * find, findAndModify, delete, and update).
@@ -32,5 +30,5 @@ interface Explainable extends Executable
      *
      * @return array
      */
-    public function getCommandDocument(Server $server);
+    public function getCommandDocument();
 }
diff --git a/src/Operation/Find.php b/src/Operation/Find.php
index a2e25b8a5..01929c60e 100644
--- a/src/Operation/Find.php
+++ b/src/Operation/Find.php
@@ -328,7 +328,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         $cmd = $this->createCommandDocument();
 
diff --git a/src/Operation/FindAndModify.php b/src/Operation/FindAndModify.php
index 42d35692f..b8f9ce99a 100644
--- a/src/Operation/FindAndModify.php
+++ b/src/Operation/FindAndModify.php
@@ -260,7 +260,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         return $this->createCommandDocument();
     }
diff --git a/src/Operation/FindOne.php b/src/Operation/FindOne.php
index b70443c83..095ffaf1a 100644
--- a/src/Operation/FindOne.php
+++ b/src/Operation/FindOne.php
@@ -134,8 +134,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->find->getCommandDocument($server);
+        return $this->find->getCommandDocument();
     }
 }
diff --git a/src/Operation/FindOneAndDelete.php b/src/Operation/FindOneAndDelete.php
index 7ce9ee7c4..362d04346 100644
--- a/src/Operation/FindOneAndDelete.php
+++ b/src/Operation/FindOneAndDelete.php
@@ -122,8 +122,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->findAndModify->getCommandDocument($server);
+        return $this->findAndModify->getCommandDocument();
     }
 }
diff --git a/src/Operation/FindOneAndReplace.php b/src/Operation/FindOneAndReplace.php
index 4132985cd..5ec774e47 100644
--- a/src/Operation/FindOneAndReplace.php
+++ b/src/Operation/FindOneAndReplace.php
@@ -175,8 +175,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->findAndModify->getCommandDocument($server);
+        return $this->findAndModify->getCommandDocument();
     }
 }
diff --git a/src/Operation/FindOneAndUpdate.php b/src/Operation/FindOneAndUpdate.php
index 88bea8bd9..5df15076a 100644
--- a/src/Operation/FindOneAndUpdate.php
+++ b/src/Operation/FindOneAndUpdate.php
@@ -169,8 +169,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->findAndModify->getCommandDocument($server);
+        return $this->findAndModify->getCommandDocument();
     }
 }
diff --git a/src/Operation/Update.php b/src/Operation/Update.php
index ddf09c572..64f71d4ed 100644
--- a/src/Operation/Update.php
+++ b/src/Operation/Update.php
@@ -219,7 +219,7 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
         $cmd = ['update' => $this->collectionName, 'updates' => [['q' => $this->filter, 'u' => $this->update] + $this->createUpdateOptions()]];
 
diff --git a/src/Operation/UpdateMany.php b/src/Operation/UpdateMany.php
index a7002baf5..b4c0062cd 100644
--- a/src/Operation/UpdateMany.php
+++ b/src/Operation/UpdateMany.php
@@ -120,8 +120,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->update->getCommandDocument($server);
+        return $this->update->getCommandDocument();
     }
 }
diff --git a/src/Operation/UpdateOne.php b/src/Operation/UpdateOne.php
index 63436c0e7..581acea35 100644
--- a/src/Operation/UpdateOne.php
+++ b/src/Operation/UpdateOne.php
@@ -120,8 +120,8 @@ public function execute(Server $server)
      * @see Explainable::getCommandDocument()
      * @return array
      */
-    public function getCommandDocument(Server $server)
+    public function getCommandDocument()
     {
-        return $this->update->getCommandDocument($server);
+        return $this->update->getCommandDocument();
     }
 }

From 58559e3d63a70d3a08cfc943b5fd59ebf2cc7abb Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Mon, 12 Jun 2023 18:28:27 -0400
Subject: [PATCH 307/321] PHPLIB-1120: Remove redundant options from
 with_transaction() docs examples (#1103)

---
 tests/DocumentationExamplesTest.php | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index a5b368809..748f5b81d 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -1799,13 +1799,7 @@ public function testWithTransactionExample(): void
 
         // Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error).
 
-        $transactionOptions = [
-            'readConcern' => new \MongoDB\Driver\ReadConcern(\MongoDB\Driver\ReadConcern::LOCAL),
-            'writeConcern' => new \MongoDB\Driver\WriteConcern(\MongoDB\Driver\WriteConcern::MAJORITY, 1000),
-            'readPreference' => new \MongoDB\Driver\ReadPreference(\MongoDB\Driver\ReadPreference::PRIMARY),
-        ];
-
-        \MongoDB\with_transaction($session, $callback, $transactionOptions);
+        \MongoDB\with_transaction($session, $callback);
 
         // End Transactions withTxn API Example 1
         // phpcs:enable

From 7e9df62f88c6b9edbc0057c5e3cfa7e3f62793c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Tue, 13 Jun 2023 12:08:24 +0200
Subject: [PATCH 308/321] PHPLIB-1063: Import writeConcernError in unified
 tests (#1090)

Synced with mongodb/specifications@3880a6ab41d495c1fbe88b49f2d67347ea128dd2

https://github.com/mongodb/specifications/blob/3880a6ab41d495c1fbe88b49f2d67347ea128dd2/source/command-logging-and-monitoring/tests/monitoring/writeConcernError.json
---
 .../command-monitoring/writeConcernError.json | 155 ++++++++++++++++++
 1 file changed, 155 insertions(+)
 create mode 100644 tests/UnifiedSpecTests/command-monitoring/writeConcernError.json

diff --git a/tests/UnifiedSpecTests/command-monitoring/writeConcernError.json b/tests/UnifiedSpecTests/command-monitoring/writeConcernError.json
new file mode 100644
index 000000000..7bc16f2ab
--- /dev/null
+++ b/tests/UnifiedSpecTests/command-monitoring/writeConcernError.json
@@ -0,0 +1,155 @@
+{
+  "description": "writeConcernError",
+  "schemaVersion": "1.4",
+  "runOnRequirements": [
+    {
+      "minServerVersion": "4.1.0",
+      "topologies": [
+        "replicaset"
+      ],
+      "serverless": "forbid"
+    }
+  ],
+  "createEntities": [
+    {
+      "client": {
+        "id": "client",
+        "observeEvents": [
+          "commandStartedEvent",
+          "commandSucceededEvent",
+          "commandFailedEvent"
+        ]
+      }
+    },
+    {
+      "database": {
+        "id": "database",
+        "client": "client",
+        "databaseName": "command-monitoring-tests"
+      }
+    },
+    {
+      "collection": {
+        "id": "collection",
+        "database": "database",
+        "collectionName": "test"
+      }
+    }
+  ],
+  "initialData": [
+    {
+      "collectionName": "test",
+      "databaseName": "command-monitoring-tests",
+      "documents": [
+        {
+          "_id": 1,
+          "x": 11
+        }
+      ]
+    }
+  ],
+  "tests": [
+    {
+      "description": "A retryable write with write concern errors publishes success event",
+      "operations": [
+        {
+          "name": "failPoint",
+          "object": "testRunner",
+          "arguments": {
+            "client": "client",
+            "failPoint": {
+              "configureFailPoint": "failCommand",
+              "mode": {
+                "times": 1
+              },
+              "data": {
+                "failCommands": [
+                  "insert"
+                ],
+                "writeConcernError": {
+                  "code": 91,
+                  "errorLabels": [
+                    "RetryableWriteError"
+                  ]
+                }
+              }
+            }
+          }
+        },
+        {
+          "name": "insertOne",
+          "object": "collection",
+          "arguments": {
+            "document": {
+              "_id": 2,
+              "x": 22
+            }
+          }
+        }
+      ],
+      "expectEvents": [
+        {
+          "client": "client",
+          "events": [
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "test",
+                  "documents": [
+                    {
+                      "_id": 2,
+                      "x": 22
+                    }
+                  ],
+                  "ordered": true
+                },
+                "commandName": "insert",
+                "databaseName": "command-monitoring-tests"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "reply": {
+                  "ok": 1,
+                  "n": 1,
+                  "writeConcernError": {
+                    "code": 91,
+                    "errorLabels": [
+                      "RetryableWriteError"
+                    ]
+                  }
+                },
+                "commandName": "insert"
+              }
+            },
+            {
+              "commandStartedEvent": {
+                "command": {
+                  "insert": "test",
+                  "documents": [
+                    {
+                      "_id": 2,
+                      "x": 22
+                    }
+                  ],
+                  "ordered": true
+                },
+                "commandName": "insert",
+                "databaseName": "command-monitoring-tests"
+              }
+            },
+            {
+              "commandSucceededEvent": {
+                "reply": {
+                  "ok": 1,
+                  "n": 1
+                },
+                "commandName": "insert"
+              }
+            }
+          ]
+        }
+      ]
+    }
+  ]
+}

From 7e63041e6ea4c626f4fe187acfc8494b92025f29 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Tue, 13 Jun 2023 15:42:46 +0200
Subject: [PATCH 309/321] PHPLIB-1123: Use `array_is_list` (#1093)

---
 composer.json                            |  3 ++-
 psalm-baseline.xml                       |  6 +++---
 src/Operation/Aggregate.php              | 11 ++++-------
 src/Operation/BulkWrite.php              | 11 ++++-------
 src/Operation/CreateCollection.php       | 14 +++++++-------
 src/Operation/CreateIndexes.php          | 11 ++++-------
 src/Operation/InsertMany.php             | 11 ++++-------
 src/functions.php                        | 13 +++++--------
 tests/Operation/AggregateTest.php        |  2 +-
 tests/Operation/BulkWriteTest.php        |  2 +-
 tests/Operation/CreateCollectionTest.php |  2 +-
 tests/Operation/CreateIndexesTest.php    |  2 +-
 tests/Operation/InsertManyTest.php       |  2 +-
 tests/Operation/WatchTest.php            |  2 +-
 14 files changed, 39 insertions(+), 53 deletions(-)

diff --git a/composer.json b/composer.json
index 772723852..fe9698d0e 100644
--- a/composer.json
+++ b/composer.json
@@ -15,7 +15,8 @@
         "ext-mongodb": "^1.16.0",
         "jean85/pretty-package-versions": "^2.0.1",
         "symfony/polyfill-php73": "^1.27",
-        "symfony/polyfill-php80": "^1.27"
+        "symfony/polyfill-php80": "^1.27",
+        "symfony/polyfill-php81": "^1.27"
     },
     "require-dev": {
         "doctrine/coding-standard": "^11.1",
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index b8640c4f2..dcc159ab8 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -417,13 +417,13 @@
     
   
   
-    
-      $i
+    
       $i
       $this->options['typeMap']
     
-    
+    
       $cmd[$option]
+      $i
       $options['session']
       $options['writeConcern']
     
diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php
index 010194dff..48a892d80 100644
--- a/src/Operation/Aggregate.php
+++ b/src/Operation/Aggregate.php
@@ -31,6 +31,7 @@
 use MongoDB\Exception\UnsupportedException;
 use stdClass;
 
+use function array_is_list;
 use function current;
 use function is_array;
 use function is_bool;
@@ -137,18 +138,14 @@ class Aggregate implements Executable, Explainable
      */
     public function __construct(string $databaseName, ?string $collectionName, array $pipeline, array $options = [])
     {
-        $expectedIndex = 0;
+        if (! array_is_list($pipeline)) {
+            throw new InvalidArgumentException('$pipeline is not a list');
+        }
 
         foreach ($pipeline as $i => $operation) {
-            if ($i !== $expectedIndex) {
-                throw new InvalidArgumentException(sprintf('$pipeline is not a list (unexpected index: "%s")', $i));
-            }
-
             if (! is_array($operation) && ! is_object($operation)) {
                 throw InvalidArgumentException::invalidType(sprintf('$pipeline[%d]', $i), $operation, 'array or object');
             }
-
-            $expectedIndex += 1;
         }
 
         $options += ['useCursor' => true];
diff --git a/src/Operation/BulkWrite.php b/src/Operation/BulkWrite.php
index b68daed4d..e104d5d73 100644
--- a/src/Operation/BulkWrite.php
+++ b/src/Operation/BulkWrite.php
@@ -26,6 +26,7 @@
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Exception\UnsupportedException;
 
+use function array_is_list;
 use function array_key_exists;
 use function count;
 use function current;
@@ -132,13 +133,11 @@ public function __construct(string $databaseName, string $collectionName, array
             throw new InvalidArgumentException('$operations is empty');
         }
 
-        $expectedIndex = 0;
+        if (! array_is_list($operations)) {
+            throw new InvalidArgumentException('$operations is not a list');
+        }
 
         foreach ($operations as $i => $operation) {
-            if ($i !== $expectedIndex) {
-                throw new InvalidArgumentException(sprintf('$operations is not a list (unexpected index: "%s")', $i));
-            }
-
             if (! is_array($operation)) {
                 throw InvalidArgumentException::invalidType(sprintf('$operations[%d]', $i), $operation, 'array');
             }
@@ -271,8 +270,6 @@ public function __construct(string $databaseName, string $collectionName, array
                 default:
                     throw new InvalidArgumentException(sprintf('Unknown operation type "%s" in $operations[%d]', $type, $i));
             }
-
-            $expectedIndex += 1;
         }
 
         $options += ['ordered' => true];
diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php
index a4cc721c0..db85e172d 100644
--- a/src/Operation/CreateCollection.php
+++ b/src/Operation/CreateCollection.php
@@ -24,6 +24,8 @@
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 
+use function array_is_list;
+use function assert;
 use function current;
 use function is_array;
 use function is_bool;
@@ -241,18 +243,16 @@ public function __construct(string $databaseName, string $collectionName, array
         }
 
         if (isset($options['pipeline'])) {
-            $expectedIndex = 0;
+            $pipeline = $options['pipeline'];
+            assert(is_array($pipeline));
+            if (! array_is_list($pipeline)) {
+                throw new InvalidArgumentException('The "pipeline" option is not a list');
+            }
 
             foreach ($options['pipeline'] as $i => $operation) {
-                if ($i !== $expectedIndex) {
-                    throw new InvalidArgumentException(sprintf('The "pipeline" option is not a list (unexpected index: "%s")', $i));
-                }
-
                 if (! is_array($operation) && ! is_object($operation)) {
                     throw InvalidArgumentException::invalidType(sprintf('$options["pipeline"][%d]', $i), $operation, 'array or object');
                 }
-
-                $expectedIndex += 1;
             }
         }
 
diff --git a/src/Operation/CreateIndexes.php b/src/Operation/CreateIndexes.php
index 0b3ed2728..1b8414fd8 100644
--- a/src/Operation/CreateIndexes.php
+++ b/src/Operation/CreateIndexes.php
@@ -26,6 +26,7 @@
 use MongoDB\Exception\UnsupportedException;
 use MongoDB\Model\IndexInput;
 
+use function array_is_list;
 use function array_map;
 use function is_array;
 use function is_integer;
@@ -88,20 +89,16 @@ public function __construct(string $databaseName, string $collectionName, array
             throw new InvalidArgumentException('$indexes is empty');
         }
 
-        $expectedIndex = 0;
+        if (! array_is_list($indexes)) {
+            throw new InvalidArgumentException('$indexes is not a list');
+        }
 
         foreach ($indexes as $i => $index) {
-            if ($i !== $expectedIndex) {
-                throw new InvalidArgumentException(sprintf('$indexes is not a list (unexpected index: "%s")', $i));
-            }
-
             if (! is_array($index)) {
                 throw InvalidArgumentException::invalidType(sprintf('$index[%d]', $i), $index, 'array');
             }
 
             $this->indexes[] = new IndexInput($index);
-
-            $expectedIndex += 1;
         }
 
         if (isset($options['commitQuorum']) && ! is_string($options['commitQuorum']) && ! is_integer($options['commitQuorum'])) {
diff --git a/src/Operation/InsertMany.php b/src/Operation/InsertMany.php
index 816315dcd..a257d069c 100644
--- a/src/Operation/InsertMany.php
+++ b/src/Operation/InsertMany.php
@@ -26,6 +26,7 @@
 use MongoDB\Exception\UnsupportedException;
 use MongoDB\InsertManyResult;
 
+use function array_is_list;
 use function is_array;
 use function is_bool;
 use function is_object;
@@ -84,18 +85,14 @@ public function __construct(string $databaseName, string $collectionName, array
             throw new InvalidArgumentException('$documents is empty');
         }
 
-        $expectedIndex = 0;
+        if (! array_is_list($documents)) {
+            throw new InvalidArgumentException('$documents is not a list');
+        }
 
         foreach ($documents as $i => $document) {
-            if ($i !== $expectedIndex) {
-                throw new InvalidArgumentException(sprintf('$documents is not a list (unexpected index: "%s")', $i));
-            }
-
             if (! is_array($document) && ! is_object($document)) {
                 throw InvalidArgumentException::invalidType(sprintf('$documents[%d]', $i), $document, 'array or object');
             }
-
-            $expectedIndex += 1;
         }
 
         $options += ['ordered' => true];
diff --git a/src/functions.php b/src/functions.php
index 5d4e0add3..b3a14dd9e 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -34,6 +34,7 @@
 use ReflectionClass;
 use ReflectionException;
 
+use function array_is_list;
 use function array_key_first;
 use function assert;
 use function end;
@@ -260,19 +261,15 @@ function is_pipeline($pipeline, bool $allowEmpty = false): bool
         return $allowEmpty;
     }
 
-    $expectedKey = 0;
+    if (! array_is_list($pipeline)) {
+        return false;
+    }
 
-    foreach ($pipeline as $key => $stage) {
+    foreach ($pipeline as $stage) {
         if (! is_array($stage) && ! is_object($stage)) {
             return false;
         }
 
-        if ($expectedKey !== $key) {
-            return false;
-        }
-
-        $expectedKey++;
-
         if (! is_first_key_operator($stage)) {
             return false;
         }
diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php
index 3ce450ad7..7e9a66e85 100644
--- a/tests/Operation/AggregateTest.php
+++ b/tests/Operation/AggregateTest.php
@@ -10,7 +10,7 @@ class AggregateTest extends TestCase
     public function testConstructorPipelineArgumentMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$pipeline is not a list (unexpected index: "1")');
+        $this->expectExceptionMessage('$pipeline is not a list');
         new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [1 => ['$match' => ['x' => 1]]]);
     }
 
diff --git a/tests/Operation/BulkWriteTest.php b/tests/Operation/BulkWriteTest.php
index ac21e558e..444178cf7 100644
--- a/tests/Operation/BulkWriteTest.php
+++ b/tests/Operation/BulkWriteTest.php
@@ -17,7 +17,7 @@ public function testOperationsMustNotBeEmpty(): void
     public function testOperationsMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$operations is not a list (unexpected index: "1")');
+        $this->expectExceptionMessage('$operations is not a list');
         new BulkWrite($this->getDatabaseName(), $this->getCollectionName(), [
             1 => [BulkWrite::INSERT_ONE => [['x' => 1]]],
         ]);
diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php
index c3e58b0a2..5be217f8f 100644
--- a/tests/Operation/CreateCollectionTest.php
+++ b/tests/Operation/CreateCollectionTest.php
@@ -10,7 +10,7 @@ class CreateCollectionTest extends TestCase
     public function testConstructorPipelineOptionMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('The "pipeline" option is not a list (unexpected index: "1")');
+        $this->expectExceptionMessage('The "pipeline" option is not a list');
         new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['pipeline' => [1 => ['$match' => ['x' => 1]]]]);
     }
 
diff --git a/tests/Operation/CreateIndexesTest.php b/tests/Operation/CreateIndexesTest.php
index 80db10078..74c386f30 100644
--- a/tests/Operation/CreateIndexesTest.php
+++ b/tests/Operation/CreateIndexesTest.php
@@ -14,7 +14,7 @@ class CreateIndexesTest extends TestCase
     public function testConstructorIndexesArgumentMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$indexes is not a list (unexpected index: "1")');
+        $this->expectExceptionMessage('$indexes is not a list');
         new CreateIndexes($this->getDatabaseName(), $this->getCollectionName(), [1 => ['key' => ['x' => 1]]]);
     }
 
diff --git a/tests/Operation/InsertManyTest.php b/tests/Operation/InsertManyTest.php
index eb283a970..67d91418e 100644
--- a/tests/Operation/InsertManyTest.php
+++ b/tests/Operation/InsertManyTest.php
@@ -17,7 +17,7 @@ public function testConstructorDocumentsMustNotBeEmpty(): void
     public function testConstructorDocumentsMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$documents is not a list (unexpected index: "1")');
+        $this->expectExceptionMessage('$documents is not a list');
         new InsertMany($this->getDatabaseName(), $this->getCollectionName(), [1 => ['x' => 1]]);
     }
 
diff --git a/tests/Operation/WatchTest.php b/tests/Operation/WatchTest.php
index 64c490fa2..30b45a13e 100644
--- a/tests/Operation/WatchTest.php
+++ b/tests/Operation/WatchTest.php
@@ -23,7 +23,7 @@ public function testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull():
     public function testConstructorPipelineArgumentMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$pipeline is not a list (unexpected index: "foo")');
+        $this->expectExceptionMessage('$pipeline is not a list');
 
         /* Note: Watch uses array_unshift() to prepend the $changeStream stage
          * to the pipeline. Since array_unshift() reindexes numeric keys, we'll

From b3607d91b71b4efb2d92e52e68073308c9696b39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Tue, 13 Jun 2023 17:14:20 +0200
Subject: [PATCH 310/321] PHPLIB-1057: Deprecate method
 IndexInfo::isGeoHaystack() (#1085)

MongoDB 5.0 removes support for "geoHaystack" indexes, the method "IndexInfo::isGeoHaystack()" will be removed in a future release
---
 .../MongoDBModelIndexInfo-isGeoHaystack.txt   |  7 ++---
 src/Model/IndexInfo.php                       |  6 ++++
 tests/Model/IndexInfoFunctionalTest.php       |  4 ++-
 tests/Model/IndexInfoTest.php                 | 28 ++++++++++++++-----
 4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt b/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt
index 97f844f10..f6c2007df 100644
--- a/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt
+++ b/docs/reference/method/MongoDBModelIndexInfo-isGeoHaystack.txt
@@ -4,6 +4,9 @@ MongoDB\\Model\\IndexInfo::isGeoHaystack()
 
 .. versionadded:: 1.4
 
+.. deprecated:: 1.16
+   MongoDB 5.0 and later no longer supports geoHaystack indexes.
+
 .. default-domain:: mongodb
 
 .. contents:: On this page
@@ -24,10 +27,6 @@ Definition
 
       function isGeoHaystack(): boolean
 
-   .. note::
-
-      MongoDB 5.0 and later no longer supports geoHaystack indexes.
-
 Return Values
 -------------
 
diff --git a/src/Model/IndexInfo.php b/src/Model/IndexInfo.php
index ce4b2af8a..4d86bab16 100644
--- a/src/Model/IndexInfo.php
+++ b/src/Model/IndexInfo.php
@@ -23,6 +23,9 @@
 
 use function array_key_exists;
 use function array_search;
+use function trigger_error;
+
+use const E_USER_DEPRECATED;
 
 /**
  * Index information model class.
@@ -124,9 +127,12 @@ public function is2dSphere()
      * Return whether or not this index is of type geoHaystack.
      *
      * @return boolean
+     * @deprecated Since 1.16: MongoDB 5.0 removes support for geoHaystack indexes.
      */
     public function isGeoHaystack()
     {
+        trigger_error('MongoDB 5.0 removes support for "geoHaystack" indexes, the method "IndexInfo::isGeoHaystack()" will be removed in a future release', E_USER_DEPRECATED);
+
         return array_search('geoHaystack', $this->getKey(), true) !== false;
     }
 
diff --git a/tests/Model/IndexInfoFunctionalTest.php b/tests/Model/IndexInfoFunctionalTest.php
index f7e19e513..a45a97724 100644
--- a/tests/Model/IndexInfoFunctionalTest.php
+++ b/tests/Model/IndexInfoFunctionalTest.php
@@ -50,7 +50,9 @@ public function testIsGeoHaystack(): void
         $index = $result->current();
 
         $this->assertEquals($indexName, $index->getName());
-        $this->assertTrue($index->isGeoHaystack());
+        $this->assertDeprecated(function () use ($index): void {
+            $this->assertTrue($index->isGeoHaystack());
+        });
         $this->assertEquals(5, $index['bucketSize']);
     }
 
diff --git a/tests/Model/IndexInfoTest.php b/tests/Model/IndexInfoTest.php
index b4c482597..30cb26aea 100644
--- a/tests/Model/IndexInfoTest.php
+++ b/tests/Model/IndexInfoTest.php
@@ -22,7 +22,9 @@ public function testBasicIndex(): void
         $this->assertSame('x_1', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertFalse($info->is2dSphere());
-        $this->assertFalse($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertFalse($info->isGeoHaystack());
+        });
         $this->assertFalse($info->isSparse());
         $this->assertFalse($info->isText());
         $this->assertFalse($info->isTtl());
@@ -44,7 +46,9 @@ public function testSparseIndex(): void
         $this->assertSame('y_sparse', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertFalse($info->is2dSphere());
-        $this->assertFalse($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertFalse($info->isGeoHaystack());
+        });
         $this->assertTrue($info->isSparse());
         $this->assertFalse($info->isText());
         $this->assertFalse($info->isTtl());
@@ -66,7 +70,9 @@ public function testUniqueIndex(): void
         $this->assertSame('z_unique', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertFalse($info->is2dSphere());
-        $this->assertFalse($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertFalse($info->isGeoHaystack());
+        });
         $this->assertFalse($info->isSparse());
         $this->assertFalse($info->isText());
         $this->assertFalse($info->isTtl());
@@ -88,7 +94,9 @@ public function testTtlIndex(): void
         $this->assertSame('z_unique', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertFalse($info->is2dSphere());
-        $this->assertFalse($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertFalse($info->isGeoHaystack());
+        });
         $this->assertFalse($info->isSparse());
         $this->assertFalse($info->isText());
         $this->assertTrue($info->isTtl());
@@ -166,7 +174,9 @@ public function testIs2dSphere(): void
         $this->assertSame('pos_2dsphere', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertTrue($info->is2dSphere());
-        $this->assertFalse($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertFalse($info->isGeoHaystack());
+        });
         $this->assertFalse($info->isSparse());
         $this->assertFalse($info->isText());
         $this->assertFalse($info->isTtl());
@@ -187,7 +197,9 @@ public function testIsGeoHaystack(): void
         $this->assertSame('pos2_geoHaystack_x_1', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertFalse($info->is2dSphere());
-        $this->assertTrue($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertTrue($info->isGeoHaystack());
+        });
         $this->assertFalse($info->isSparse());
         $this->assertFalse($info->isText());
         $this->assertFalse($info->isTtl());
@@ -208,7 +220,9 @@ public function testIsText(): void
         $this->assertSame('title_text_description_text', $info->getName());
         $this->assertSame('foo.bar', $info->getNamespace());
         $this->assertFalse($info->is2dSphere());
-        $this->assertFalse($info->isGeoHaystack());
+        $this->assertDeprecated(function () use ($info): void {
+            $this->assertFalse($info->isGeoHaystack());
+        });
         $this->assertFalse($info->isSparse());
         $this->assertTrue($info->isText());
         $this->assertFalse($info->isTtl());

From 8c999d19fcc6be7018689dc13d3c9bfa98164492 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Wed, 14 Jun 2023 16:25:39 +0200
Subject: [PATCH 311/321] PHPLIB-881: Consolidate validation of aggregation
 pipeline options (#1078)

- Use MongoDB\is_pipeline to detect or validate pipelines
- Use standard wording for "Aggregation pipeline"
---
 psalm-baseline.xml                       |  2 +-
 src/Client.php                           |  2 +-
 src/Collection.php                       |  4 ++--
 src/Database.php                         |  4 ++--
 src/Operation/Aggregate.php              | 15 ++++-----------
 src/Operation/CreateCollection.php       | 18 +++---------------
 src/Operation/Watch.php                  |  2 +-
 src/functions.php                        |  2 +-
 tests/FunctionsTest.php                  |  7 +++++--
 tests/Operation/AggregateTest.php        |  2 +-
 tests/Operation/CreateCollectionTest.php |  2 +-
 tests/Operation/WatchTest.php            |  2 +-
 12 files changed, 23 insertions(+), 39 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index dcc159ab8..7a6d55420 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -418,7 +418,7 @@
   
   
     
-      $i
+      $options['pipeline']
       $this->options['typeMap']
     
     
diff --git a/src/Client.php b/src/Client.php
index 93ff71f6b..5b9eedea4 100644
--- a/src/Client.php
+++ b/src/Client.php
@@ -352,7 +352,7 @@ public function startSession(array $options = [])
      * Create a change stream for watching changes to the cluster.
      *
      * @see Watch::__construct() for supported options
-     * @param array $pipeline List of pipeline operations
+     * @param array $pipeline Aggregation pipeline
      * @param array $options  Command options
      * @return ChangeStream
      * @throws InvalidArgumentException for parameter/option parsing errors
diff --git a/src/Collection.php b/src/Collection.php
index 61e020db5..d92dc66da 100644
--- a/src/Collection.php
+++ b/src/Collection.php
@@ -199,7 +199,7 @@ public function __toString()
      * "result" array from the command response document.
      *
      * @see Aggregate::__construct() for supported options
-     * @param array $pipeline List of pipeline operations
+     * @param array $pipeline Aggregation pipeline
      * @param array $options  Command options
      * @return Traversable
      * @throws UnexpectedValueException if the command response was malformed
@@ -1105,7 +1105,7 @@ public function updateOne($filter, $update, array $options = [])
      * Create a change stream for watching changes to the collection.
      *
      * @see Watch::__construct() for supported options
-     * @param array $pipeline List of pipeline operations
+     * @param array $pipeline Aggregation pipeline
      * @param array $options  Command options
      * @return ChangeStream
      * @throws InvalidArgumentException for parameter/option parsing errors
diff --git a/src/Database.php b/src/Database.php
index 9c09969b6..f2f9278b5 100644
--- a/src/Database.php
+++ b/src/Database.php
@@ -187,7 +187,7 @@ public function __toString()
      * and $listLocalSessions. Requires MongoDB >= 3.6
      *
      * @see Aggregate::__construct() for supported options
-     * @param array $pipeline List of pipeline operations
+     * @param array $pipeline Aggregation pipeline
      * @param array $options  Command options
      * @return Traversable
      * @throws UnexpectedValueException if the command response was malformed
@@ -598,7 +598,7 @@ public function selectGridFSBucket(array $options = [])
      * Create a change stream for watching changes to the database.
      *
      * @see Watch::__construct() for supported options
-     * @param array $pipeline List of pipeline operations
+     * @param array $pipeline Aggregation pipeline
      * @param array $options  Command options
      * @return ChangeStream
      * @throws InvalidArgumentException for parameter/option parsing errors
diff --git a/src/Operation/Aggregate.php b/src/Operation/Aggregate.php
index 48a892d80..4d6c5867c 100644
--- a/src/Operation/Aggregate.php
+++ b/src/Operation/Aggregate.php
@@ -31,7 +31,6 @@
 use MongoDB\Exception\UnsupportedException;
 use stdClass;
 
-use function array_is_list;
 use function current;
 use function is_array;
 use function is_bool;
@@ -40,7 +39,7 @@
 use function is_string;
 use function MongoDB\create_field_path_type_map;
 use function MongoDB\is_last_pipeline_operator_write;
-use function sprintf;
+use function MongoDB\is_pipeline;
 
 /**
  * Operation for the aggregate command.
@@ -132,20 +131,14 @@ class Aggregate implements Executable, Explainable
      *
      * @param string      $databaseName   Database name
      * @param string|null $collectionName Collection name
-     * @param array       $pipeline       List of pipeline operations
+     * @param array       $pipeline       Aggregation pipeline
      * @param array       $options        Command options
      * @throws InvalidArgumentException for parameter/option parsing errors
      */
     public function __construct(string $databaseName, ?string $collectionName, array $pipeline, array $options = [])
     {
-        if (! array_is_list($pipeline)) {
-            throw new InvalidArgumentException('$pipeline is not a list');
-        }
-
-        foreach ($pipeline as $i => $operation) {
-            if (! is_array($operation) && ! is_object($operation)) {
-                throw InvalidArgumentException::invalidType(sprintf('$pipeline[%d]', $i), $operation, 'array or object');
-            }
+        if (! is_pipeline($pipeline, true /* allowEmpty */)) {
+            throw new InvalidArgumentException('$pipeline is not a valid aggregation pipeline');
         }
 
         $options += ['useCursor' => true];
diff --git a/src/Operation/CreateCollection.php b/src/Operation/CreateCollection.php
index db85e172d..eff5ab955 100644
--- a/src/Operation/CreateCollection.php
+++ b/src/Operation/CreateCollection.php
@@ -24,15 +24,13 @@
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 
-use function array_is_list;
-use function assert;
 use function current;
 use function is_array;
 use function is_bool;
 use function is_integer;
 use function is_object;
 use function is_string;
-use function sprintf;
+use function MongoDB\is_pipeline;
 use function trigger_error;
 
 use const E_USER_DEPRECATED;
@@ -242,18 +240,8 @@ public function __construct(string $databaseName, string $collectionName, array
             trigger_error('The "autoIndexId" option is deprecated and will be removed in a future release', E_USER_DEPRECATED);
         }
 
-        if (isset($options['pipeline'])) {
-            $pipeline = $options['pipeline'];
-            assert(is_array($pipeline));
-            if (! array_is_list($pipeline)) {
-                throw new InvalidArgumentException('The "pipeline" option is not a list');
-            }
-
-            foreach ($options['pipeline'] as $i => $operation) {
-                if (! is_array($operation) && ! is_object($operation)) {
-                    throw InvalidArgumentException::invalidType(sprintf('$options["pipeline"][%d]', $i), $operation, 'array or object');
-                }
-            }
+        if (isset($options['pipeline']) && ! is_pipeline($options['pipeline'], true /* allowEmpty */)) {
+            throw new InvalidArgumentException('"pipeline" option is not a valid aggregation pipeline');
         }
 
         $this->databaseName = $databaseName;
diff --git a/src/Operation/Watch.php b/src/Operation/Watch.php
index db04cb3f3..df230a72f 100644
--- a/src/Operation/Watch.php
+++ b/src/Operation/Watch.php
@@ -196,7 +196,7 @@ class Watch implements Executable, /* @internal */ CommandSubscriber
      * @param Manager     $manager        Manager instance from the driver
      * @param string|null $databaseName   Database name
      * @param string|null $collectionName Collection name
-     * @param array       $pipeline       List of pipeline operations
+     * @param array       $pipeline       Aggregation pipeline
      * @param array       $options        Command options
      * @throws InvalidArgumentException for parameter/option parsing errors
      */
diff --git a/src/functions.php b/src/functions.php
index b3a14dd9e..81e4359b4 100644
--- a/src/functions.php
+++ b/src/functions.php
@@ -300,7 +300,7 @@ function is_in_transaction(array $options): bool
  * executed against a primary server.
  *
  * @internal
- * @param array $pipeline List of pipeline operations
+ * @param array $pipeline Aggregation pipeline
  */
 function is_last_pipeline_operator_write(array $pipeline): bool
 {
diff --git a/tests/FunctionsTest.php b/tests/FunctionsTest.php
index 386124627..86fe31deb 100644
--- a/tests/FunctionsTest.php
+++ b/tests/FunctionsTest.php
@@ -243,9 +243,9 @@ public function testIsLastPipelineOperatorWrite(callable $cast): void
     }
 
     /** @dataProvider providePipelines */
-    public function testIsPipeline($expected, $pipeline): void
+    public function testIsPipeline($expected, $pipeline, $allowEmpty = false): void
     {
-        $this->assertSame($expected, is_pipeline($pipeline));
+        $this->assertSame($expected, is_pipeline($pipeline, $allowEmpty));
     }
 
     public function providePipelines(): array
@@ -286,6 +286,9 @@ public function providePipelines(): array
             'invalid pipeline element type: Serializable' => [false, new BSONArray([new BSONArray([])])],
             'invalid pipeline element type: PackedArray' => [false, PackedArray::fromPHP([[]])],
             // Empty array has no pipeline stages
+            'valid empty: array' => [true, [], true],
+            'valid empty: Serializable' => [true, new BSONArray([]), true],
+            'valid empty: PackedArray' => [true, PackedArray::fromPHP([]), true],
             'invalid empty: array' => [false, []],
             'invalid empty: Serializable' => [false, new BSONArray([])],
             'invalid empty: PackedArray' => [false, PackedArray::fromPHP([])],
diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php
index 7e9a66e85..b046e8583 100644
--- a/tests/Operation/AggregateTest.php
+++ b/tests/Operation/AggregateTest.php
@@ -10,7 +10,7 @@ class AggregateTest extends TestCase
     public function testConstructorPipelineArgumentMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$pipeline is not a list');
+        $this->expectExceptionMessage('$pipeline is not a valid aggregation pipeline');
         new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [1 => ['$match' => ['x' => 1]]]);
     }
 
diff --git a/tests/Operation/CreateCollectionTest.php b/tests/Operation/CreateCollectionTest.php
index 5be217f8f..dab0140f9 100644
--- a/tests/Operation/CreateCollectionTest.php
+++ b/tests/Operation/CreateCollectionTest.php
@@ -10,7 +10,7 @@ class CreateCollectionTest extends TestCase
     public function testConstructorPipelineOptionMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('The "pipeline" option is not a list');
+        $this->expectExceptionMessage('"pipeline" option is not a valid aggregation pipeline');
         new CreateCollection($this->getDatabaseName(), $this->getCollectionName(), ['pipeline' => [1 => ['$match' => ['x' => 1]]]]);
     }
 
diff --git a/tests/Operation/WatchTest.php b/tests/Operation/WatchTest.php
index 30b45a13e..5c07d8d18 100644
--- a/tests/Operation/WatchTest.php
+++ b/tests/Operation/WatchTest.php
@@ -23,7 +23,7 @@ public function testConstructorCollectionNameShouldBeNullIfDatabaseNameIsNull():
     public function testConstructorPipelineArgumentMustBeAList(): void
     {
         $this->expectException(InvalidArgumentException::class);
-        $this->expectExceptionMessage('$pipeline is not a list');
+        $this->expectExceptionMessage('$pipeline is not a valid aggregation pipeline');
 
         /* Note: Watch uses array_unshift() to prepend the $changeStream stage
          * to the pipeline. Since array_unshift() reindexes numeric keys, we'll

From 4fd79aca21a0275dec3ff512525cbc1f1e5d1e3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Wed, 14 Jun 2023 17:31:10 +0200
Subject: [PATCH 312/321] PHPLIB-1142: Use `disableMD5` when provided to GridFS
 Bucket constructor (#1104)

Support for the disableMD5 option of to the Bucket constructor for file uploads
Bugfix, the option value set to the constructor was ignored.
Add functional test on gridfs option passed to the constructor
---
 src/GridFS/Bucket.php                 |  6 +++++-
 tests/GridFS/BucketFunctionalTest.php | 27 +++++++++++++++++++++++++++
 tests/GridFS/FunctionalTestCase.php   |  4 ++--
 3 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/src/GridFS/Bucket.php b/src/GridFS/Bucket.php
index 3dba068e8..b58c7bda8 100644
--- a/src/GridFS/Bucket.php
+++ b/src/GridFS/Bucket.php
@@ -198,6 +198,7 @@ public function __debugInfo()
         return [
             'bucketName' => $this->bucketName,
             'databaseName' => $this->databaseName,
+            'disableMD5' => $this->disableMD5,
             'manager' => $this->manager,
             'chunkSizeBytes' => $this->chunkSizeBytes,
             'readConcern' => $this->readConcern,
@@ -547,7 +548,10 @@ public function openDownloadStreamByName(string $filename, array $options = [])
      */
     public function openUploadStream(string $filename, array $options = [])
     {
-        $options += ['chunkSizeBytes' => $this->chunkSizeBytes];
+        $options += [
+            'chunkSizeBytes' => $this->chunkSizeBytes,
+            'disableMD5' => $this->disableMD5,
+        ];
 
         $path = $this->createPathForUpload();
         $context = stream_context_create([
diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php
index 395feaa95..27a22ff90 100644
--- a/tests/GridFS/BucketFunctionalTest.php
+++ b/tests/GridFS/BucketFunctionalTest.php
@@ -53,6 +53,7 @@ public function testValidConstructorOptions(): void
             'readConcern' => new ReadConcern(ReadConcern::LOCAL),
             'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
             'writeConcern' => new WriteConcern(WriteConcern::MAJORITY, 1000),
+            'disableMD5' => true,
         ]);
     }
 
@@ -669,6 +670,32 @@ public function testUploadingAnEmptyFile(): void
         $this->assertSameDocument($expected, $fileDocument);
     }
 
+    public function testDisableMD5(): void
+    {
+        $options = ['disableMD5' => true];
+        $id = $this->bucket->uploadFromStream('filename', $this->createStream('data'), $options);
+
+        $fileDocument = $this->filesCollection->findOne(
+            ['_id' => $id]
+        );
+
+        $this->assertArrayNotHasKey('md5', $fileDocument);
+    }
+
+    public function testDisableMD5OptionInConstructor(): void
+    {
+        $options = ['disableMD5' => true];
+
+        $this->bucket = new Bucket($this->manager, $this->getDatabaseName(), $options);
+        $id = $this->bucket->uploadFromStream('filename', $this->createStream('data'));
+
+        $fileDocument = $this->filesCollection->findOne(
+            ['_id' => $id]
+        );
+
+        $this->assertArrayNotHasKey('md5', $fileDocument);
+    }
+
     public function testUploadingFirstFileCreatesIndexes(): void
     {
         $this->bucket->uploadFromStream('filename', $this->createStream('foo'));
diff --git a/tests/GridFS/FunctionalTestCase.php b/tests/GridFS/FunctionalTestCase.php
index d78b1e6b1..c22143f20 100644
--- a/tests/GridFS/FunctionalTestCase.php
+++ b/tests/GridFS/FunctionalTestCase.php
@@ -33,8 +33,8 @@ public function setUp(): void
         $this->bucket = new Bucket($this->manager, $this->getDatabaseName());
         $this->bucket->drop();
 
-        $this->chunksCollection = new Collection($this->manager, $this->getDatabaseName(), 'fs.chunks');
-        $this->filesCollection = new Collection($this->manager, $this->getDatabaseName(), 'fs.files');
+        $this->chunksCollection = $this->createCollection($this->getDatabaseName(), 'fs.chunks');
+        $this->filesCollection = $this->createCollection($this->getDatabaseName(), 'fs.files');
     }
 
     /**

From 2f09005709baede6e827cdd74acd1753e4f91c3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 15 Jun 2023 09:52:57 +0200
Subject: [PATCH 313/321] PHPLIB-1149: Use consistent terminology when
 referring to the MongoDB shell in docs (#1106)

---
 docs/reference/method/MongoDBDatabase-createCollection.txt | 2 +-
 docs/upgrade.txt                                           | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/docs/reference/method/MongoDBDatabase-createCollection.txt b/docs/reference/method/MongoDBDatabase-createCollection.txt
index 758ad6c2a..56129b975 100644
--- a/docs/reference/method/MongoDBDatabase-createCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-createCollection.txt
@@ -26,7 +26,7 @@ Definition
    collection. You may also explicitly create a collection with specific options
    using the :phpmethod:`MongoDB\\Database::createCollection()` method, or using
    :manual:`db.createCollection() ` in
-   the :program:`mongo` shell.
+   the MongoDB shell.
 
    Explicitly creating collections enables you to create
    :manual:`capped collections `, specify
diff --git a/docs/upgrade.txt b/docs/upgrade.txt
index d73d57e6c..50da6f2fe 100644
--- a/docs/upgrade.txt
+++ b/docs/upgrade.txt
@@ -336,7 +336,7 @@ operation, has been removed in favor of explicitly using
 :phpmethod:`MongoDB\\Collection::replaceOne()` (with the ``upsert`` option).
 
 While the ``save`` method does have its uses for interactive environments, such
-as the ``mongo`` shell, it was intentionally excluded from the
+as the MongoDB shell, it was intentionally excluded from the
 `CRUD specification `_
 for language drivers. Generally, application code should know if the document
 has an identifier and be able to explicitly insert or replace the document and

From 78cc92542e8710925e6a8f8cffee54051f4385b9 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Thu, 15 Jun 2023 14:06:47 -0400
Subject: [PATCH 314/321] PHPLIB-1130: Remove preview notice for CSFLE
 Queryable Encryption (#1108)

---
 ...MongoDBDatabase-method-createCollection-option.yaml | 10 +---------
 docs/includes/apiargs-dropCollection-option.yaml       |  8 --------
 .../MongoDBDatabase-createEncryptedCollection.txt      |  8 --------
 docs/tutorial/client-side-encryption.txt               |  6 +-----
 4 files changed, 2 insertions(+), 30 deletions(-)

diff --git a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
index f40cbf94b..ceb7dd075 100644
--- a/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
+++ b/docs/includes/apiargs-MongoDBDatabase-method-createCollection-option.yaml
@@ -86,17 +86,9 @@ description: |
   `Field Encryption and Queryability `_
   in the MongoDB manual for more information.
 
-  This option is available in MongoDB 6.0+ and will result in an exception at
+  This option is available in MongoDB 7.0+ and will result in an exception at
   execution time if specified for an older server version.
 
-  .. note::
-
-     Queryable Encryption is in public preview and available for evaluation
-     purposes. It is not yet recommended for production deployments as breaking
-     changes may be introduced. See the
-     `Queryable Encryption Preview `_
-     blog post for more information.
-
   .. versionadded:: 1.13
 interface: phpmethod
 operation: ~
diff --git a/docs/includes/apiargs-dropCollection-option.yaml b/docs/includes/apiargs-dropCollection-option.yaml
index 46ad66075..158c4a438 100644
--- a/docs/includes/apiargs-dropCollection-option.yaml
+++ b/docs/includes/apiargs-dropCollection-option.yaml
@@ -15,14 +15,6 @@ description: |
      This option is not passed to the :manual:`drop `
      command. The library uses it to determine related metadata collections that
      should be dropped in addition to an encrypted collection.
-
-  .. note::
-
-     Queryable Encryption is in public preview and available for evaluation
-     purposes. It is not yet recommended for production deployments as breaking
-     changes may be introduced. See the
-     `Queryable Encryption Preview `_
-     blog post for more information.
 interface: phpmethod
 operation: ~
 optional: true
diff --git a/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt b/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt
index 07dc082c1..64c643f03 100644
--- a/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt
+++ b/docs/reference/method/MongoDBDatabase-createEncryptedCollection.txt
@@ -12,14 +12,6 @@ MongoDB\\Database::createEncryptedCollection()
    :depth: 1
    :class: singlecol
 
-.. note::
-
-   Queryable Encryption is in public preview and available for evaluation
-   purposes. It is not yet recommended for production deployments as breaking
-   changes may be introduced. See the
-   `Queryable Encryption Preview `_
-   blog post for more information.
-
 Definition
 ----------
 
diff --git a/docs/tutorial/client-side-encryption.txt b/docs/tutorial/client-side-encryption.txt
index bbb8196db..efff2e7d4 100644
--- a/docs/tutorial/client-side-encryption.txt
+++ b/docs/tutorial/client-side-encryption.txt
@@ -285,11 +285,7 @@ Automatic Queryable Encryption
 .. note::
 
    Automatic queryable encryption is an enterprise only feature and requires
-   MongoDB 6.0+. Queryable Encryption is in public preview and available for
-   evaluation purposes. It is not yet recommended for production deployments as
-   breaking changes may be introduced. See the
-   `Queryable Encryption Preview `_
-   blog post for more information.
+   MongoDB 7.0+.
 
 The following example uses a local key; however, other key providers such as AWS
 are also an option. The data in the ``encryptedIndexed`` and

From 4e849c841cc7e4b2b2470d0df6c72e85aee19708 Mon Sep 17 00:00:00 2001
From: Jeremy Mikola 
Date: Fri, 16 Jun 2023 15:05:30 -0400
Subject: [PATCH 315/321] PHPLIB-1133: Enable QEv2 tests on serverless (#1110)

This only affects legacy spec tests. Prose tests were never explicitly skipped on serverless and only required a 7.0+ server.

Synced with mongodb/specifications@840e6d49c354656bff11b2622f0d3001b39d9403
---
 .../client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json | 1 -
 tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json | 1 -
 .../client-side-encryption/tests/fle2v2-CreateCollection.json    | 1 -
 .../client-side-encryption/tests/fle2v2-DecryptExistingData.json | 1 -
 tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json  | 1 -
 .../tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json      | 1 -
 .../tests/fle2v2-EncryptedFields-vs-jsonSchema.json              | 1 -
 .../tests/fle2v2-EncryptedFieldsMap-defaults.json                | 1 -
 .../client-side-encryption/tests/fle2v2-FindOneAndUpdate.json    | 1 -
 .../client-side-encryption/tests/fle2v2-InsertFind-Indexed.json  | 1 -
 .../tests/fle2v2-InsertFind-Unindexed.json                       | 1 -
 .../client-side-encryption/tests/fle2v2-MissingKey.json          | 1 -
 .../client-side-encryption/tests/fle2v2-NoEncryption.json        | 1 -
 .../tests/fle2v2-Range-Date-Aggregate.json                       | 1 -
 .../tests/fle2v2-Range-Date-Correctness.json                     | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Date-Delete.json   | 1 -
 .../tests/fle2v2-Range-Date-FindOneAndUpdate.json                | 1 -
 .../tests/fle2v2-Range-Date-InsertFind.json                      | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Date-Update.json   | 1 -
 .../tests/fle2v2-Range-Decimal-Aggregate.json                    | 1 -
 .../tests/fle2v2-Range-Decimal-Correctness.json                  | 1 -
 .../tests/fle2v2-Range-Decimal-Delete.json                       | 1 -
 .../tests/fle2v2-Range-Decimal-FindOneAndUpdate.json             | 1 -
 .../tests/fle2v2-Range-Decimal-InsertFind.json                   | 1 -
 .../tests/fle2v2-Range-Decimal-Update.json                       | 1 -
 .../tests/fle2v2-Range-DecimalPrecision-Aggregate.json           | 1 -
 .../tests/fle2v2-Range-DecimalPrecision-Correctness.json         | 1 -
 .../tests/fle2v2-Range-DecimalPrecision-Delete.json              | 1 -
 .../tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json    | 1 -
 .../tests/fle2v2-Range-DecimalPrecision-InsertFind.json          | 1 -
 .../tests/fle2v2-Range-DecimalPrecision-Update.json              | 1 -
 .../tests/fle2v2-Range-Double-Aggregate.json                     | 1 -
 .../tests/fle2v2-Range-Double-Correctness.json                   | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Double-Delete.json | 1 -
 .../tests/fle2v2-Range-Double-FindOneAndUpdate.json              | 1 -
 .../tests/fle2v2-Range-Double-InsertFind.json                    | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Double-Update.json | 1 -
 .../tests/fle2v2-Range-DoublePrecision-Aggregate.json            | 1 -
 .../tests/fle2v2-Range-DoublePrecision-Correctness.json          | 1 -
 .../tests/fle2v2-Range-DoublePrecision-Delete.json               | 1 -
 .../tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json     | 1 -
 .../tests/fle2v2-Range-DoublePrecision-InsertFind.json           | 1 -
 .../tests/fle2v2-Range-DoublePrecision-Update.json               | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json | 1 -
 .../tests/fle2v2-Range-Int-Correctness.json                      | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Int-Delete.json    | 1 -
 .../tests/fle2v2-Range-Int-FindOneAndUpdate.json                 | 1 -
 .../tests/fle2v2-Range-Int-InsertFind.json                       | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Int-Update.json    | 1 -
 .../tests/fle2v2-Range-Long-Aggregate.json                       | 1 -
 .../tests/fle2v2-Range-Long-Correctness.json                     | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Long-Delete.json   | 1 -
 .../tests/fle2v2-Range-Long-FindOneAndUpdate.json                | 1 -
 .../tests/fle2v2-Range-Long-InsertFind.json                      | 1 -
 .../client-side-encryption/tests/fle2v2-Range-Long-Update.json   | 1 -
 .../client-side-encryption/tests/fle2v2-Range-WrongType.json     | 1 -
 tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json  | 1 -
 .../tests/fle2v2-validatorAndPartialFieldExpression.json         | 1 -
 58 files changed, 58 deletions(-)

diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
index dcc3983ae..9b28df2f9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-BypassQueryAnalysis.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
index e47c689bf..27310cb59 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Compact.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
index cc8bd1714..c324be8ab 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-CreateCollection.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json
index 905d3c945..1fb4c1d1b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-DecryptExistingData.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
index e4150eab8..ddfe57b00 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
index b579979e9..bdc5c99bc 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-EncryptedFieldsMap.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
index 0a84d7365..8e0c6dafa 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFields-vs-jsonSchema.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
index 3e0905ead..1c0a057ca 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-EncryptedFieldsMap-defaults.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
index 4606fbb93..c5e689a3d 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
index c7149d1f5..6e156ffc6 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Indexed.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
index 008b0c959..48280f5bd 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-InsertFind-Unindexed.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
index 0b7e86bca..8812a1f0a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-MissingKey.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json
index 185691d61..a6843c473 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-NoEncryption.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
index dea821bd1..ba53b007b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
index 9e4f52587..e9620efbe 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
index 7f4094f50..daaa09389 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
index 5ec060160..8500fa829 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
index efce1511c..7de45ba00 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
index 7f9fadcda..d5b62be06 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Date-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
index fb129392b..081bc577f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
index 5120aecb7..12fe7c8bc 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
index de81159b4..ac49d16a2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
index 36cf91c88..88a235078 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
index 6b5a642aa..54e43e4a2 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
index 8cfb7b525..b2b8136a9 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Decimal-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset"
       ]
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
index 801beefe1..b078d1817 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
index b8a695361..0859e702a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
index 1abb59bfd..6e1ad90cd 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
index 8d763431f..1cfd19a1e 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
index 5407fba18..da7660972 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
index e5d1a4e05..2d201948c 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DecimalPrecision-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
index d8c9cacdc..c188f1f5a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
index 65594bcb1..3e298127d 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
index 392e722f1..dc0ba435f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
index bbcfb321f..4b96575e1 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
index 9f2c7c991..4827b6838 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
index ce03576f8..c3284ad0f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Double-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
index b121c72f1..a2c1f3b75 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
index 6b42ecfe8..d0c0601ce 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
index a5c397d0b..a617442ee 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
index b6df9463e..5565fb179 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
index 1cea25545..a1d8c1785 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
index 7703c9057..6ea99242b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-DoublePrecision-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
index 9c2536264..b3b2826fa 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
index 58ccf3efc..4932223ba 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
index b20b2750b..03f816e4b 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
index f9c189ace..d573f7b6a 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
index 874d4760c..04953663f 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
index c2b62b4d1..4c7a3c278 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Int-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
index afc0f97be..a7e77fd5c 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Aggregate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
index cda941de8..365822c79 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Correctness.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
index ad344e21b..17a01fe07 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Delete.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
index d44720046..918d0dfee 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-FindOneAndUpdate.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
index 4eb837f28..9fafd10d4 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-InsertFind.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
index 3ba7f17c1..20ac25bfa 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-Long-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
index e5e9ddc82..5a6e650ab 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Range-WrongType.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
index 14104e2cd..cb260edc0 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-Update.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",
diff --git a/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json b/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
index 4adf6fc07..901c4dd84 100644
--- a/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
+++ b/tests/SpecTests/client-side-encryption/tests/fle2v2-validatorAndPartialFieldExpression.json
@@ -2,7 +2,6 @@
   "runOn": [
     {
       "minServerVersion": "7.0.0",
-      "serverless": "forbid",
       "topology": [
         "replicaset",
         "sharded",

From 53052b6fba9962144b4b109e3def6e914a427cec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Mon, 19 Jun 2023 10:12:07 +0200
Subject: [PATCH 316/321] PHPLIB-1144: Add unit tests on
 `Explainable::getCommandDocument()` (#1105)

* PHPLIB-1144: Add unit tests on Explainable::getCommandDocument

* Add tests on FindOneAnd*::getCommandDocument

* Refactor Find::getCommandDocument

Remove private function createCommandDocument introduced by c7b2b033b327b29a619ee0ed2bcd9d055b4ab9d1 and used only for the explain command.

* Add let and comment to explain delete

Separate Intentionally omitted option

* Aggregate option explain is incompatible with the explain command

The 'explain' option is illegal when a explain verbosity is also provided

* Let the server throw errors
---
 psalm-baseline.xml                        |  2 +-
 src/Operation/Delete.php                  | 12 ++++-
 src/Operation/Find.php                    | 15 ------
 tests/Operation/AggregateTest.php         | 40 +++++++++++++++
 tests/Operation/CountTest.php             | 28 +++++++++++
 tests/Operation/DeleteTest.php            | 29 +++++++++++
 tests/Operation/DistinctTest.php          | 27 ++++++++++
 tests/Operation/FindAndModifyTest.php     | 43 ++++++++++++++++
 tests/Operation/FindOneAndDeleteTest.php  | 32 ++++++++++++
 tests/Operation/FindOneAndReplaceTest.php | 37 ++++++++++++++
 tests/Operation/FindOneAndUpdateTest.php  | 40 +++++++++++++++
 tests/Operation/FindTest.php              | 60 +++++++++++++++++++++++
 tests/Operation/UpdateTest.php            | 34 +++++++++++++
 13 files changed, 382 insertions(+), 17 deletions(-)

diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index 7a6d55420..b9f153751 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -471,7 +471,7 @@
       $this->options['writeConcern']
     
     
-      $cmd['writeConcern']
+      $cmd['comment']
       $deleteOptions['hint']
       $options['comment']
       $options['session']
diff --git a/src/Operation/Delete.php b/src/Operation/Delete.php
index 48fe99470..5f3318012 100644
--- a/src/Operation/Delete.php
+++ b/src/Operation/Delete.php
@@ -177,7 +177,17 @@ public function execute(Server $server)
      */
     public function getCommandDocument()
     {
-        return ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]];
+        $cmd = ['delete' => $this->collectionName, 'deletes' => [['q' => $this->filter] + $this->createDeleteOptions()]];
+
+        if (isset($this->options['comment'])) {
+            $cmd['comment'] = $this->options['comment'];
+        }
+
+        if (isset($this->options['let'])) {
+            $cmd['let'] = (object) $this->options['let'];
+        }
+
+        return $cmd;
     }
 
     /**
diff --git a/src/Operation/Find.php b/src/Operation/Find.php
index 01929c60e..8725d37e8 100644
--- a/src/Operation/Find.php
+++ b/src/Operation/Find.php
@@ -329,21 +329,6 @@ public function execute(Server $server)
      * @return array
      */
     public function getCommandDocument()
-    {
-        $cmd = $this->createCommandDocument();
-
-        // Read concern can change the query plan
-        if (isset($this->options['readConcern'])) {
-            $cmd['readConcern'] = $this->options['readConcern'];
-        }
-
-        return $cmd;
-    }
-
-    /**
-     * Construct a command document for Find
-     */
-    private function createCommandDocument(): array
     {
         $cmd = ['find' => $this->collectionName, 'filter' => (object) $this->filter];
 
diff --git a/tests/Operation/AggregateTest.php b/tests/Operation/AggregateTest.php
index b046e8583..f72fc5a22 100644
--- a/tests/Operation/AggregateTest.php
+++ b/tests/Operation/AggregateTest.php
@@ -2,6 +2,9 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\ReadConcern;
+use MongoDB\Driver\ReadPreference;
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\Aggregate;
 
@@ -104,4 +107,41 @@ private function getInvalidHintValues()
     {
         return [123, 3.14, true];
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'allowDiskUse' => true,
+            'batchSize' => 100,
+            'bypassDocumentValidation' => true,
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'let' => ['a' => 1],
+            'maxTimeMS' => 100,
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+            'useCursor' => true,
+            // Intentionally omitted options
+            // The "explain" option is illegal
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
+            'typeMap' => ['root' => 'array', 'document' => 'array'],
+            'writeConcern' => new WriteConcern(0),
+        ];
+        $operation = new Aggregate($this->getDatabaseName(), $this->getCollectionName(), [['$project' => ['_id' => 0]]], $options);
+
+        $expected = [
+            'aggregate' => $this->getCollectionName(),
+            'pipeline' => [['$project' => ['_id' => 0]]],
+            'allowDiskUse' => true,
+            'bypassDocumentValidation' => true,
+            'collation' => (object) ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+            'let' => (object) ['a' => 1],
+            'cursor' => ['batchSize' => 100],
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/CountTest.php b/tests/Operation/CountTest.php
index 23969595c..5259a9d44 100644
--- a/tests/Operation/CountTest.php
+++ b/tests/Operation/CountTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\ReadConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\Count;
 
@@ -64,4 +65,31 @@ private function getInvalidHintValues()
     {
         return [123, 3.14, true];
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'hint' => '_id_',
+            'limit' => 10,
+            'skip' => 20,
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'maxTimeMS' => 100,
+        ];
+        $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $options);
+
+        $expected = [
+            'count' => $this->getCollectionName(),
+            'query' => (object) ['x' => 1],
+            'collation' => (object) ['locale' => 'fr'],
+            'hint' => '_id_',
+            'comment' => 'explain me',
+            'limit' => 10,
+            'skip' => 20,
+            'maxTimeMS' => 100,
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/DeleteTest.php b/tests/Operation/DeleteTest.php
index acdbefc31..90b9cae52 100644
--- a/tests/Operation/DeleteTest.php
+++ b/tests/Operation/DeleteTest.php
@@ -7,6 +7,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\Delete;
 use TypeError;
@@ -65,4 +66,32 @@ public function provideInvalidConstructorOptions()
 
         return $options;
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'collation' => ['locale' => 'fr'],
+            'hint' => '_id_',
+            'let' => ['a' => 1],
+            'comment' => 'explain me',
+            // Intentionally omitted options
+            'writeConcern' => new WriteConcern(0),
+        ];
+        $operation = new Delete($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], 0, $options);
+
+        $expected = [
+            'delete' => $this->getCollectionName(),
+            'deletes' => [
+                [
+                    'q' => ['x' => 1],
+                    'limit' => 0,
+                    'collation' => (object) ['locale' => 'fr'],
+                    'hint' => '_id_',
+                ],
+            ],
+            'comment' => 'explain me',
+            'let' => (object) ['a' => 1],
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/DistinctTest.php b/tests/Operation/DistinctTest.php
index 8473e833d..9ece08fa5 100644
--- a/tests/Operation/DistinctTest.php
+++ b/tests/Operation/DistinctTest.php
@@ -2,6 +2,8 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\ReadConcern;
+use MongoDB\Driver\ReadPreference;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\Distinct;
 
@@ -51,4 +53,29 @@ public function provideInvalidConstructorOptions()
 
         return $options;
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'collation' => ['locale' => 'fr'],
+            'maxTimeMS' => 100,
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+            'comment' => 'explain me',
+            // Intentionally omitted options
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
+            'typeMap' => ['root' => 'array'],
+        ];
+        $operation = new Distinct($this->getDatabaseName(), $this->getCollectionName(), 'f', ['x' => 1], $options);
+
+        $expected = [
+            'distinct' => $this->getCollectionName(),
+            'key' => 'f',
+            'query' => (object) ['x' => 1],
+            'collation' => (object) ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'maxTimeMS' => 100,
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/FindAndModifyTest.php b/tests/Operation/FindAndModifyTest.php
index 3904385e9..a0738bb12 100644
--- a/tests/Operation/FindAndModifyTest.php
+++ b/tests/Operation/FindAndModifyTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\FindAndModify;
 
@@ -83,4 +84,46 @@ public function testConstructorUpdateAndRemoveOptionsAreMutuallyExclusive(): voi
         $this->expectExceptionMessage('The "remove" option must be true or an "update" document must be specified, but not both');
         new FindAndModify($this->getDatabaseName(), $this->getCollectionName(), ['remove' => true, 'update' => []]);
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'arrayFilters' => [['x' => 1]],
+            'bypassDocumentValidation' => true,
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'fields' => ['_id' => 0],
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+            'new' => true,
+            'query' => ['y' => 2],
+            'sort' => ['x' => 1],
+            'update' => ['$set' => ['x' => 2]],
+            'upsert' => true,
+            'let' => ['a' => 3],
+            // Intentionally omitted options
+            'remove' => false, // When "update" is set
+            'typeMap' => ['root' => 'array'],
+            'writeConcern' => new WriteConcern(0),
+        ];
+        $operation = new FindAndModify($this->getDatabaseName(), $this->getCollectionName(), $options);
+
+        $expected = [
+            'findAndModify' => $this->getCollectionName(),
+            'new' => true,
+            'upsert' => true,
+            'collation' => (object) ['locale' => 'fr'],
+            'fields' => (object) ['_id' => 0],
+            'let' => (object) ['a' => 3],
+            'query' => (object) ['y' => 2],
+            'sort' => (object) ['x' => 1],
+            'update' => (object) ['$set' => ['x' => 2]],
+            'arrayFilters' =>  [['x' => 1]],
+            'bypassDocumentValidation' => true,
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/FindOneAndDeleteTest.php b/tests/Operation/FindOneAndDeleteTest.php
index 42055ba27..e63062ace 100644
--- a/tests/Operation/FindOneAndDeleteTest.php
+++ b/tests/Operation/FindOneAndDeleteTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\FindOneAndDelete;
 
@@ -31,4 +32,35 @@ public function provideInvalidConstructorOptions()
 
         return $options;
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+            'sort' => ['x' => 1],
+            'let' => ['a' => 3],
+            // Intentionally omitted options
+            'projection' => ['_id' => 0],
+            'typeMap' => ['root' => 'array'],
+            'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
+        ];
+        $operation = new FindOneAndDelete($this->getDatabaseName(), $this->getCollectionName(), ['y' => 2], $options);
+
+        $expected = [
+            'findAndModify' => $this->getCollectionName(),
+            'collation' => (object) ['locale' => 'fr'],
+            'fields' => (object) ['_id' => 0],
+            'let' => (object) ['a' => 3],
+            'query' => (object) ['y' => 2],
+            'sort' => (object) ['x' => 1],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+            'remove' => true,
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/FindOneAndReplaceTest.php b/tests/Operation/FindOneAndReplaceTest.php
index b084036f4..743098e4f 100644
--- a/tests/Operation/FindOneAndReplaceTest.php
+++ b/tests/Operation/FindOneAndReplaceTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\FindOneAndReplace;
 
@@ -82,4 +83,40 @@ public function provideInvalidConstructorReturnDocumentOptions()
     {
         return $this->wrapValuesForDataProvider([-1, 0, 3]);
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'bypassDocumentValidation' => true,
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'fields' => ['_id' => 0],
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+            'projection' => ['_id' => 0],
+            'sort' => ['x' => 1],
+            'let' => ['a' => 3],
+            // Intentionally omitted options
+            'returnDocument' => FindOneAndReplace::RETURN_DOCUMENT_AFTER,
+            'typeMap' => ['root' => 'array'],
+            'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
+        ];
+        $operation = new FindOneAndReplace($this->getDatabaseName(), $this->getCollectionName(), ['y' => 2], ['y' => 3], $options);
+
+        $expected = [
+            'findAndModify' => $this->getCollectionName(),
+            'new' => true,
+            'collation' => (object) ['locale' => 'fr'],
+            'fields' => (object) ['_id' => 0],
+            'let' => (object) ['a' => 3],
+            'query' => (object) ['y' => 2],
+            'sort' => (object) ['x' => 1],
+            'update' => (object) ['y' => 3],
+            'bypassDocumentValidation' => true,
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/FindOneAndUpdateTest.php b/tests/Operation/FindOneAndUpdateTest.php
index 8514cea86..d174b73f3 100644
--- a/tests/Operation/FindOneAndUpdateTest.php
+++ b/tests/Operation/FindOneAndUpdateTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\FindOneAndUpdate;
 
@@ -65,4 +66,43 @@ public function provideInvalidConstructorReturnDocumentOptions()
     {
         return $this->wrapValuesForDataProvider([-1, 0, 3]);
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'arrayFilters' => [['x' => 1]],
+            'bypassDocumentValidation' => true,
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+            'sort' => ['x' => 1],
+            'upsert' => true,
+            'let' => ['a' => 3],
+            // Intentionally omitted options
+            'projection' => ['_id' => 0],
+            'returnDocument' => FindOneAndUpdate::RETURN_DOCUMENT_AFTER,
+            'typeMap' => ['root' => 'array'],
+            'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
+        ];
+        $operation = new FindOneAndUpdate($this->getDatabaseName(), $this->getCollectionName(), ['y' => 2], ['$set' => ['x' => 2]], $options);
+
+        $expected = [
+            'findAndModify' => $this->getCollectionName(),
+            'new' => true,
+            'upsert' => true,
+            'collation' => (object) ['locale' => 'fr'],
+            'fields' => (object) ['_id' => 0],
+            'let' => (object) ['a' => 3],
+            'query' => (object) ['y' => 2],
+            'sort' => (object) ['x' => 1],
+            'update' => (object) ['$set' => ['x' => 2]],
+            'arrayFilters' =>  [['x' => 1]],
+            'bypassDocumentValidation' => true,
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'maxTimeMS' => 100,
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/FindTest.php b/tests/Operation/FindTest.php
index f5889f260..1da7d23fa 100644
--- a/tests/Operation/FindTest.php
+++ b/tests/Operation/FindTest.php
@@ -2,6 +2,8 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\ReadConcern;
+use MongoDB\Driver\ReadPreference;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\Find;
 
@@ -154,4 +156,62 @@ public function provideInvalidConstructorCursorTypeOptions()
     {
         return $this->wrapValuesForDataProvider([-1, 0, 4]);
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        // all options except deprecated "snapshot" and "maxScan"
+        $options = [
+            'allowDiskUse' => true,
+            'allowPartialResults' => true,
+            'batchSize' => 123,
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'limit' => 15,
+            'max' => ['x' => 100],
+            'maxTimeMS' => 100,
+            'min' => ['x' => 10],
+            'noCursorTimeout' => true,
+            'oplogReplay' => true,
+            'projection' => ['_id' => 0],
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+            'returnKey' => true,
+            'showRecordId' => true,
+            'skip' => 5,
+            'sort' => ['x' => 1],
+            'let' => ['y' => 2],
+            // Intentionally omitted options
+            'cursorType' => Find::NON_TAILABLE,
+            'maxAwaitTimeMS' => 500,
+            'modifiers' => ['foo' => 'bar'],
+            'readPreference' => new ReadPreference(ReadPreference::SECONDARY_PREFERRED),
+            'typeMap' => ['root' => 'array'],
+        ];
+        $operation = new Find($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $options);
+
+        $expected = [
+            'find' => $this->getCollectionName(),
+            'filter' => (object) ['x' => 1],
+            'allowDiskUse' => true,
+            'allowPartialResults' => true,
+            'batchSize' => 123,
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'limit' => 15,
+            'maxTimeMS' => 100,
+            'noCursorTimeout' => true,
+            'oplogReplay' => true,
+            'projection' => ['_id' => 0],
+            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
+            'returnKey' => true,
+            'showRecordId' => true,
+            'skip' => 5,
+            'sort' => ['x' => 1],
+            'collation' => (object) ['locale' => 'fr'],
+            'let' => (object) ['y' => 2],
+            'max' => (object) ['x' => 100],
+            'min' => (object) ['x' => 10],
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }
diff --git a/tests/Operation/UpdateTest.php b/tests/Operation/UpdateTest.php
index bcc445544..de9fcbadd 100644
--- a/tests/Operation/UpdateTest.php
+++ b/tests/Operation/UpdateTest.php
@@ -2,6 +2,7 @@
 
 namespace MongoDB\Tests\Operation;
 
+use MongoDB\Driver\WriteConcern;
 use MongoDB\Exception\InvalidArgumentException;
 use MongoDB\Operation\Update;
 
@@ -75,4 +76,37 @@ public function testConstructorMultiOptionProhibitsReplacementDocumentOrEmptyPip
         $this->expectExceptionMessage('"multi" option cannot be true unless $update has update operator(s) or non-empty pipeline');
         new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], $update, ['multi' => true]);
     }
+
+    public function testExplainableCommandDocument(): void
+    {
+        $options = [
+            'arrayFilters' => [['x' => 1]],
+            'bypassDocumentValidation' => true,
+            'collation' => ['locale' => 'fr'],
+            'comment' => 'explain me',
+            'hint' => '_id_',
+            'multi' => true,
+            'upsert' => true,
+            'let' => ['a' => 3],
+            'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
+        ];
+        $operation = new Update($this->getDatabaseName(), $this->getCollectionName(), ['x' => 1], ['$set' => ['x' => 2]], $options);
+
+        $expected = [
+            'update' => $this->getCollectionName(),
+            'bypassDocumentValidation' => true,
+            'updates' => [
+                [
+                    'q' => ['x' => 1],
+                    'u' => ['$set' => ['x' => 2]],
+                    'multi' => true,
+                    'upsert' => true,
+                    'arrayFilters' => [['x' => 1]],
+                    'hint' => '_id_',
+                    'collation' => (object) ['locale' => 'fr'],
+                ],
+            ],
+        ];
+        $this->assertEquals($expected, $operation->getCommandDocument());
+    }
 }

From 5a14dee3b14f1c51f1b7f9483741b1d226f0124d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Wed, 21 Jun 2023 12:41:43 +0200
Subject: [PATCH 317/321] PHPLIB-1153: Add helper
 FunctionalTestCase::skipIfServerVersion (#1107)

---
 tests/Collection/CrudSpecFunctionalTest.php   | 28 ++------
 tests/DocumentationExamplesTest.php           | 18 ++---
 tests/FunctionalTestCase.php                  |  7 ++
 tests/Operation/BulkWriteFunctionalTest.php   |  9 +--
 ...reateEncryptedCollectionFunctionalTest.php |  5 +-
 .../Operation/CreateIndexesFunctionalTest.php |  9 +--
 tests/Operation/DeleteFunctionalTest.php      |  6 +-
 tests/Operation/ExplainFunctionalTest.php     | 10 +--
 .../Operation/FindAndModifyFunctionalTest.php | 10 +--
 tests/Operation/MapReduceFunctionalTest.php   |  8 +--
 tests/Operation/UpdateFunctionalTest.php      |  9 +--
 tests/Operation/WatchFunctionalTest.php       | 67 +++++--------------
 ...rose21_AutomaticDataEncryptionKeysTest.php |  5 +-
 .../Prose22_RangeExplicitEncryptionTest.php   |  5 +-
 .../ClientSideEncryptionSpecTest.php          |  5 +-
 tests/SpecTests/RetryableWritesSpecTest.php   |  5 +-
 16 files changed, 53 insertions(+), 153 deletions(-)

diff --git a/tests/Collection/CrudSpecFunctionalTest.php b/tests/Collection/CrudSpecFunctionalTest.php
index 620e35298..994ec915b 100644
--- a/tests/Collection/CrudSpecFunctionalTest.php
+++ b/tests/Collection/CrudSpecFunctionalTest.php
@@ -13,7 +13,6 @@
 use MongoDB\Operation\FindOneAndReplace;
 use MongoDB\UpdateResult;
 use MultipleIterator;
-use PHPUnit_Framework_SkippedTestError;
 
 use function array_diff_key;
 use function array_key_exists;
@@ -25,7 +24,6 @@
 use function sprintf;
 use function str_replace;
 use function strtolower;
-use function version_compare;
 
 /**
  * CRUD spec functional tests.
@@ -54,8 +52,12 @@ public function setUp(): void
     /** @dataProvider provideSpecificationTests */
     public function testSpecification(array $initialData, array $test, $minServerVersion, $maxServerVersion, $serverless): void
     {
-        if (isset($minServerVersion) || isset($maxServerVersion)) {
-            $this->checkServerVersion($minServerVersion, $maxServerVersion);
+        if (isset($minServerVersion)) {
+            $this->skipIfServerVersion('<', $minServerVersion);
+        }
+
+        if (isset($maxServerVersion)) {
+            $this->skipIfServerVersion('>=', $maxServerVersion);
         }
 
         $this->checkServerlessRequirement($serverless);
@@ -143,24 +145,6 @@ private function checkServerlessRequirement(?string $serverless): void
         }
     }
 
-    /**
-     * Checks that the server version is within the allowed bounds (if any).
-     *
-     * @throws PHPUnit_Framework_SkippedTestError
-     */
-    private function checkServerVersion(?string $minServerVersion, ?string $maxServerVersion): void
-    {
-        $serverVersion = $this->getServerVersion();
-
-        if (isset($minServerVersion) && version_compare($serverVersion, $minServerVersion, '<')) {
-            $this->markTestSkipped(sprintf('Server version "%s" < minServerVersion "%s"', $serverVersion, $minServerVersion));
-        }
-
-        if (isset($maxServerVersion) && version_compare($serverVersion, $maxServerVersion, '>=')) {
-            $this->markTestSkipped(sprintf('Server version "%s" >= maxServerVersion "%s"', $serverVersion, $maxServerVersion));
-        }
-    }
-
     /**
      * Executes an "operation" block.
      *
diff --git a/tests/DocumentationExamplesTest.php b/tests/DocumentationExamplesTest.php
index 748f5b81d..001057454 100644
--- a/tests/DocumentationExamplesTest.php
+++ b/tests/DocumentationExamplesTest.php
@@ -20,7 +20,6 @@
 use function ob_start;
 use function usleep;
 use function var_dump;
-use function version_compare;
 
 /**
  * Documentation examples to be parsed for inclusion in the MongoDB manual.
@@ -1549,9 +1548,7 @@ public function testCausalConsistency(): void
 
     public function testSnapshotQueries(): void
     {
-        if (version_compare($this->getServerVersion(), '5.0.0', '<')) {
-            $this->markTestSkipped('Snapshot queries outside of transactions are not supported');
-        }
+        $this->skipIfServerVersion('<', '5.0.0', 'Snapshot queries outside of transactions are not supported');
 
         if (! ($this->isReplicaSet() || $this->isShardedClusterUsingReplicasets())) {
             $this->markTestSkipped('Snapshot read concern is only supported with replicasets');
@@ -1682,13 +1679,8 @@ public function testVersionedApi(): void
 
     public function testVersionedApiMigration(): void
     {
-        if (version_compare($this->getServerVersion(), '5.0.0', '<')) {
-            $this->markTestSkipped('Versioned API is not supported');
-        }
-
-        if (version_compare($this->getServerVersion(), '5.0.9', '>=')) {
-            $this->markTestSkipped('The count command was added to API version 1 (SERVER-63850)');
-        }
+        $this->skipIfServerVersion('<', '5.0.0', 'Versioned API is not supported');
+        $this->skipIfServerVersion('>=', '5.0.9', 'The count command was added to API version 1 (SERVER-63850)');
 
         $this->dropCollection($this->getDatabaseName(), 'sales');
         $uriString = static::getUri(true);
@@ -1817,9 +1809,7 @@ public function testQueryableEncryption(): void
             $this->markTestSkipped('Queryable encryption requires replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
-            $this->markTestSkipped('Explicit encryption tests require MongoDB 7.0 or later');
-        }
+        $this->skipIfServerVersion('<', '7.0.0', 'Explicit encryption tests require MongoDB 7.0 or later');
 
         if (! $this->isEnterprise()) {
             $this->markTestSkipped('Automatic encryption requires MongoDB Enterprise');
diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php
index 0e5e7de46..b4d4fb5ab 100644
--- a/tests/FunctionalTestCase.php
+++ b/tests/FunctionalTestCase.php
@@ -484,6 +484,13 @@ protected function isShardedClusterUsingReplicasets()
         return preg_match('@^.*/.*:\d+@', $document['host']);
     }
 
+    protected function skipIfServerVersion(string $operator, string $version, ?string $message = null): void
+    {
+        if (version_compare($this->getServerVersion(), $version, $operator)) {
+            $this->markTestSkipped($message ?? sprintf('Server version is %s %s', $operator, $version));
+        }
+    }
+
     protected function skipIfChangeStreamIsNotSupported(): void
     {
         switch ($this->getPrimaryServer()->getType()) {
diff --git a/tests/Operation/BulkWriteFunctionalTest.php b/tests/Operation/BulkWriteFunctionalTest.php
index 0dbb20e67..2acb747bf 100644
--- a/tests/Operation/BulkWriteFunctionalTest.php
+++ b/tests/Operation/BulkWriteFunctionalTest.php
@@ -15,7 +15,6 @@
 use stdClass;
 
 use function is_array;
-use function version_compare;
 
 class BulkWriteFunctionalTest extends FunctionalTestCase
 {
@@ -200,8 +199,8 @@ function (array $event) use ($expectedReplacement): void {
      */
     public function testUpdateDocuments($update, $expectedUpdate): void
     {
-        if (is_array($expectedUpdate) && version_compare($this->getServerVersion(), '4.2.0', '<')) {
-            $this->markTestSkipped('Pipeline-style updates are not supported');
+        if (is_array($expectedUpdate)) {
+            $this->skipIfServerVersion('<', '4.2.0', 'Pipeline-style updates are not supported');
         }
 
         (new CommandObserver())->observe(
@@ -425,9 +424,7 @@ function (array $event): void {
 
     public function testBulkWriteWithPipelineUpdates(): void
     {
-        if (version_compare($this->getServerVersion(), '4.2.0', '<')) {
-            $this->markTestSkipped('Pipeline-style updates are not supported');
-        }
+        $this->skipIfServerVersion('<', '4.2.0', 'Pipeline-style updates are not supported');
 
         $this->createFixtures(4);
 
diff --git a/tests/Operation/CreateEncryptedCollectionFunctionalTest.php b/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
index df690dd29..b6d920ce4 100644
--- a/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
+++ b/tests/Operation/CreateEncryptedCollectionFunctionalTest.php
@@ -16,7 +16,6 @@
 use function getenv;
 use function is_executable;
 use function is_readable;
-use function version_compare;
 
 use const DIRECTORY_SEPARATOR;
 use const PATH_SEPARATOR;
@@ -42,9 +41,7 @@ public function setUp(): void
             $this->markTestSkipped('Queryable Encryption requires replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '6.0.0', '<')) {
-            $this->markTestSkipped('Queryable Encryption requires MongoDB 6.0 or later');
-        }
+        $this->skipIfServerVersion('<', '6.0.0', 'Queryable Encryption requires MongoDB 6.0 or later');
 
         $client = static::createTestClient();
 
diff --git a/tests/Operation/CreateIndexesFunctionalTest.php b/tests/Operation/CreateIndexesFunctionalTest.php
index 13deb386c..748e33bc1 100644
--- a/tests/Operation/CreateIndexesFunctionalTest.php
+++ b/tests/Operation/CreateIndexesFunctionalTest.php
@@ -16,7 +16,6 @@
 use function call_user_func;
 use function is_callable;
 use function sprintf;
-use function version_compare;
 
 class CreateIndexesFunctionalTest extends FunctionalTestCase
 {
@@ -189,9 +188,7 @@ function (array $event): void {
 
     public function testCommitQuorumOption(): void
     {
-        if (version_compare($this->getServerVersion(), '4.3.4', '<')) {
-            $this->markTestSkipped('commitQuorum is not supported');
-        }
+        $this->skipIfServerVersion('<', '4.3.4', 'commitQuorum is not supported');
 
         if ($this->getPrimaryServer()->getType() !== Server::TYPE_RS_PRIMARY) {
             $this->markTestSkipped('commitQuorum is only supported on replica sets');
@@ -216,9 +213,7 @@ function (array $event): void {
 
     public function testCommitQuorumUnsupported(): void
     {
-        if (version_compare($this->getServerVersion(), '4.3.4', '>=')) {
-            $this->markTestSkipped('commitQuorum is supported');
-        }
+        $this->skipIfServerVersion('>=', '4.3.4', 'commitQuorum is supported');
 
         $operation = new CreateIndexes(
             $this->getDatabaseName(),
diff --git a/tests/Operation/DeleteFunctionalTest.php b/tests/Operation/DeleteFunctionalTest.php
index 692441ac6..4ae84045e 100644
--- a/tests/Operation/DeleteFunctionalTest.php
+++ b/tests/Operation/DeleteFunctionalTest.php
@@ -12,8 +12,6 @@
 use MongoDB\Tests\CommandObserver;
 use stdClass;
 
-use function version_compare;
-
 class DeleteFunctionalTest extends FunctionalTestCase
 {
     /** @var Collection */
@@ -87,9 +85,7 @@ public function testDeleteMany(): void
 
     public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.4.0', '>=')) {
-            $this->markTestSkipped('hint is supported');
-        }
+        $this->skipIfServerVersion('>=', '4.4.0', 'hint is supported');
 
         $operation = new Delete(
             $this->getDatabaseName(),
diff --git a/tests/Operation/ExplainFunctionalTest.php b/tests/Operation/ExplainFunctionalTest.php
index 264289013..aa28ce8f7 100644
--- a/tests/Operation/ExplainFunctionalTest.php
+++ b/tests/Operation/ExplainFunctionalTest.php
@@ -21,8 +21,6 @@
 use MongoDB\Operation\UpdateOne;
 use MongoDB\Tests\CommandObserver;
 
-use function version_compare;
-
 class ExplainFunctionalTest extends FunctionalTestCase
 {
     /** @dataProvider provideVerbosityInformation */
@@ -329,9 +327,7 @@ public function testUpdateOne($verbosity, $executionStatsExpected, $allPlansExec
 
     public function testAggregate(): void
     {
-        if (version_compare($this->getServerVersion(), '4.0.0', '<')) {
-            $this->markTestSkipped('Explaining aggregate command requires server version >= 4.0');
-        }
+        $this->skipIfServerVersion('<', '4.0.0', 'Explaining aggregate command requires server version >= 4.0');
 
         $this->createFixtures(3);
 
@@ -348,9 +344,7 @@ public function testAggregate(): void
     /** @dataProvider provideVerbosityInformation */
     public function testAggregateOptimizedToQuery($verbosity, $executionStatsExpected, $allPlansExecutionExpected): void
     {
-        if (version_compare($this->getServerVersion(), '4.2.0', '<')) {
-            $this->markTestSkipped('MongoDB < 4.2 does not optimize simple aggregation pipelines');
-        }
+        $this->skipIfServerVersion('<', '4.2.0', 'MongoDB < 4.2 does not optimize simple aggregation pipelines');
 
         $this->createFixtures(3);
 
diff --git a/tests/Operation/FindAndModifyFunctionalTest.php b/tests/Operation/FindAndModifyFunctionalTest.php
index 22b2c9e56..ebdbd1092 100644
--- a/tests/Operation/FindAndModifyFunctionalTest.php
+++ b/tests/Operation/FindAndModifyFunctionalTest.php
@@ -12,8 +12,6 @@
 use MongoDB\Tests\CommandObserver;
 use stdClass;
 
-use function version_compare;
-
 class FindAndModifyFunctionalTest extends FunctionalTestCase
 {
     /** @dataProvider provideQueryDocuments */
@@ -129,9 +127,7 @@ function (array $event): void {
 
     public function testHintOptionUnsupportedClientSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.2.0', '>=')) {
-            $this->markTestSkipped('server reports error for unsupported findAndModify options');
-        }
+        $this->skipIfServerVersion('>=', '4.2.0', 'server reports error for unsupported findAndModify options');
 
         $operation = new FindAndModify(
             $this->getDatabaseName(),
@@ -147,9 +143,7 @@ public function testHintOptionUnsupportedClientSideError(): void
 
     public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.4.0', '>=')) {
-            $this->markTestSkipped('hint is supported');
-        }
+        $this->skipIfServerVersion('>=', '4.4.0', 'hint is supported');
 
         $operation = new FindAndModify(
             $this->getDatabaseName(),
diff --git a/tests/Operation/MapReduceFunctionalTest.php b/tests/Operation/MapReduceFunctionalTest.php
index bdb3ffc7a..55831dd2f 100644
--- a/tests/Operation/MapReduceFunctionalTest.php
+++ b/tests/Operation/MapReduceFunctionalTest.php
@@ -107,9 +107,7 @@ public function testResult(): void
 
     public function testResultIncludesTimingWithVerboseOption(): void
     {
-        if (version_compare($this->getServerVersion(), '4.3.0', '>=')) {
-            $this->markTestSkipped('mapReduce statistics are no longer exposed');
-        }
+        $this->skipIfServerVersion('>=', '4.3.0', 'mapReduce statistics are no longer exposed');
 
         $this->createFixtures(3);
 
@@ -128,9 +126,7 @@ public function testResultIncludesTimingWithVerboseOption(): void
 
     public function testResultDoesNotIncludeTimingWithoutVerboseOption(): void
     {
-        if (version_compare($this->getServerVersion(), '4.3.0', '>=')) {
-            $this->markTestSkipped('mapReduce statistics are no longer exposed');
-        }
+        $this->skipIfServerVersion('>=', '4.3.0', 'mapReduce statistics are no longer exposed');
 
         $this->createFixtures(3);
 
diff --git a/tests/Operation/UpdateFunctionalTest.php b/tests/Operation/UpdateFunctionalTest.php
index 7af2fc674..d0a92679f 100644
--- a/tests/Operation/UpdateFunctionalTest.php
+++ b/tests/Operation/UpdateFunctionalTest.php
@@ -14,7 +14,6 @@
 use stdClass;
 
 use function is_array;
-use function version_compare;
 
 class UpdateFunctionalTest extends FunctionalTestCase
 {
@@ -56,8 +55,8 @@ function (array $event) use ($expectedFilter): void {
      */
     public function testUpdateDocuments($update, $expectedUpdate): void
     {
-        if (is_array($expectedUpdate) && version_compare($this->getServerVersion(), '4.2.0', '<')) {
-            $this->markTestSkipped('Pipeline-style updates are not supported');
+        if (is_array($expectedUpdate)) {
+            $this->skipIfServerVersion('<', '4.2.0', 'Pipeline-style updates are not supported');
         }
 
         (new CommandObserver())->observe(
@@ -152,9 +151,7 @@ function (array $event): void {
 
     public function testHintOptionAndUnacknowledgedWriteConcernUnsupportedClientSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.2.0', '>=')) {
-            $this->markTestSkipped('hint is supported');
-        }
+        $this->skipIfServerVersion('>=', '4.2.0', 'hint is supported');
 
         $operation = new Update(
             $this->getDatabaseName(),
diff --git a/tests/Operation/WatchFunctionalTest.php b/tests/Operation/WatchFunctionalTest.php
index 66c8d85bd..bc633c191 100644
--- a/tests/Operation/WatchFunctionalTest.php
+++ b/tests/Operation/WatchFunctionalTest.php
@@ -29,7 +29,6 @@
 use function microtime;
 use function MongoDB\server_supports_feature;
 use function sprintf;
-use function version_compare;
 
 /**
  * @group matrix-testing-exclude-server-4.2-driver-4.0-topology-sharded_cluster
@@ -61,9 +60,7 @@ public function setUp(): void
      */
     public function testGetResumeToken(): void
     {
-        if ($this->isPostBatchResumeTokenSupported()) {
-            $this->markTestSkipped('postBatchResumeToken is supported');
-        }
+        $this->skipIfServerVersion('>=', '4.0.7', 'postBatchResumeToken is supported');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
         $changeStream = $operation->execute($this->getPrimaryServer());
@@ -108,9 +105,7 @@ public function testGetResumeToken(): void
      */
     public function testGetResumeTokenWithPostBatchResumeToken(): void
     {
-        if (! $this->isPostBatchResumeTokenSupported()) {
-            $this->markTestSkipped('postBatchResumeToken is not supported');
-        }
+        $this->skipIfServerVersion('<', '4.0.7', 'postBatchResumeToken is not supported');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
 
@@ -206,9 +201,7 @@ function (array $event) use (&$commands): void {
 
     public function testResumeBeforeReceivingAnyResultsIncludesPostBatchResumeToken(): void
     {
-        if (! $this->isPostBatchResumeTokenSupported()) {
-            $this->markTestSkipped('postBatchResumeToken is not supported');
-        }
+        $this->skipIfServerVersion('<', '4.0.7', 'postBatchResumeToken is not supported');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
 
@@ -282,9 +275,7 @@ public function testResumeBeforeReceivingAnyResultsIncludesStartAtOperationTime(
             $this->markTestSkipped('startAtOperationTime is not supported');
         }
 
-        if ($this->isPostBatchResumeTokenSupported()) {
-            $this->markTestSkipped('postBatchResumeToken takes precedence over startAtOperationTime');
-        }
+        $this->skipIfServerVersion('>=', '4.0.7', 'postBatchResumeToken takes precedence over startAtOperationTime');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
 
@@ -699,9 +690,7 @@ public function testInitialCursorIsNotClosed(): void
      */
     public function testResumeTokenNotFoundClientSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.8', '>=')) {
-            $this->markTestSkipped('Server rejects change streams that modify resume token (SERVER-37786)');
-        }
+        $this->skipIfServerVersion('>=', '4.1.8', 'Server rejects change streams that modify resume token (SERVER-37786)');
 
         $pipeline =  [['$project' => ['_id' => 0]]];
 
@@ -727,9 +716,7 @@ public function testResumeTokenNotFoundClientSideError(): void
      */
     public function testResumeTokenNotFoundServerSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.8', '<')) {
-            $this->markTestSkipped('Server does not reject change streams that modify resume token');
-        }
+        $this->skipIfServerVersion('<', '4.1.8', 'Server does not reject change streams that modify resume token');
 
         $pipeline =  [['$project' => ['_id' => 0]]];
 
@@ -750,9 +737,7 @@ public function testResumeTokenNotFoundServerSideError(): void
      */
     public function testResumeTokenInvalidTypeClientSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.8', '>=')) {
-            $this->markTestSkipped('Server rejects change streams that modify resume token (SERVER-37786)');
-        }
+        $this->skipIfServerVersion('>=', '4.1.8', 'Server rejects change streams that modify resume token (SERVER-37786)');
 
         $pipeline =  [['$project' => ['_id' => ['$literal' => 'foo']]]];
 
@@ -778,9 +763,7 @@ public function testResumeTokenInvalidTypeClientSideError(): void
      */
     public function testResumeTokenInvalidTypeServerSideError(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.8', '<')) {
-            $this->markTestSkipped('Server does not reject change streams that modify resume token');
-        }
+        $this->skipIfServerVersion('<', '4.1.8', 'Server does not reject change streams that modify resume token');
 
         $pipeline =  [['$project' => ['_id' => ['$literal' => 'foo']]]];
 
@@ -964,9 +947,7 @@ public function testResumeAfterOption(): void
 
     public function testStartAfterOption(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.1', '<')) {
-            $this->markTestSkipped('startAfter is not supported');
-        }
+        $this->skipIfServerVersion('<', '4.1.1', 'startAfter is not supported');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
         $changeStream = $operation->execute($this->getPrimaryServer());
@@ -1175,8 +1156,8 @@ function (array $event) use (&$sessionAfterResume, &$commands): void {
 
     public function testSessionFreed(): void
     {
-        if ($this->isShardedCluster() && version_compare($this->getServerVersion(), '5.1.0', '>=')) {
-            $this->markTestSkipped('mongos still reports non-zero cursor ID for invalidated change stream (SERVER-60764)');
+        if ($this->isShardedCluster()) {
+            $this->skipIfServerVersion('>=', '5.1.0', 'mongos still reports non-zero cursor ID for invalidated change stream (SERVER-60764)');
         }
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
@@ -1283,9 +1264,7 @@ function (array $aggregateCommand) {
      */
     public function testErrorDuringAggregateCommandDoesNotCauseResume(): void
     {
-        if (version_compare($this->getServerVersion(), '4.0.0', '<')) {
-            $this->markTestSkipped('failCommand is not supported');
-        }
+        $this->skipIfServerVersion('<', '4.0.0', 'failCommand is not supported');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
 
@@ -1362,9 +1341,7 @@ function () {
      */
     public function testGetResumeTokenReturnsOriginalResumeTokenOnEmptyBatch(): void
     {
-        if ($this->isPostBatchResumeTokenSupported()) {
-            $this->markTestSkipped('postBatchResumeToken is supported');
-        }
+        $this->skipIfServerVersion('>=', '4.0.7', 'postBatchResumeToken is supported');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
         $changeStream = $operation->execute($this->getPrimaryServer());
@@ -1398,10 +1375,7 @@ public function testGetResumeTokenReturnsOriginalResumeTokenOnEmptyBatch(): void
      */
     public function testResumeTokenBehaviour(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.1', '<')) {
-            $this->markTestSkipped('Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1');
-        }
-
+        $this->skipIfServerVersion('<', '4.1.1', 'Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1');
         $this->skipIfIsShardedCluster('Resume token behaviour can\'t be reliably tested on sharded clusters.');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
@@ -1457,9 +1431,7 @@ public function testResumeTokenBehaviour(): void
      */
     public function testResumingChangeStreamWithoutPreviousResultsIncludesStartAfterOption(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.1', '<')) {
-            $this->markTestSkipped('Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1');
-        }
+        $this->skipIfServerVersion('<', '4.1.1', 'Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
         $changeStream = $operation->execute($this->getPrimaryServer());
@@ -1504,9 +1476,7 @@ function (array $event) use (&$aggregateCommand): void {
      */
     public function testResumingChangeStreamWithPreviousResultsIncludesResumeAfterOption(): void
     {
-        if (version_compare($this->getServerVersion(), '4.1.1', '<')) {
-            $this->markTestSkipped('Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1');
-        }
+        $this->skipIfServerVersion('<', '4.1.1', 'Testing resumeAfter and startAfter can only be tested on servers >= 4.1.1');
 
         $operation = new Watch($this->manager, $this->getDatabaseName(), $this->getCollectionName(), [], $this->defaultOptions);
         $changeStream = $operation->execute($this->getPrimaryServer());
@@ -1596,11 +1566,6 @@ private function insertDocument($document): void
         $this->assertEquals(1, $writeResult->getInsertedCount());
     }
 
-    private function isPostBatchResumeTokenSupported()
-    {
-        return version_compare($this->getServerVersion(), '4.0.7', '>=');
-    }
-
     private function isStartAtOperationTimeSupported()
     {
         return server_supports_feature($this->getPrimaryServer(), self::$wireVersionForStartAtOperationTime);
diff --git a/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php b/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
index 91cad0e1d..ea99ca1c2 100644
--- a/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
+++ b/tests/SpecTests/ClientSideEncryption/Prose21_AutomaticDataEncryptionKeysTest.php
@@ -11,7 +11,6 @@
 use MongoDB\Exception\InvalidArgumentException;
 
 use function base64_decode;
-use function version_compare;
 
 /**
  * Prose test 21: Automatic Data Encryption Keys
@@ -35,9 +34,7 @@ public function setUp(): void
             $this->markTestSkipped('Automatic data encryption key tests require replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
-            $this->markTestSkipped('Automatic data encryption key tests require MongoDB 7.0 or later');
-        }
+        $this->skipIfServerVersion('<', '7.0.0', 'Automatic data encryption key tests require MongoDB 7.0 or later');
 
         $client = static::createTestClient();
         $this->database = $client->selectDatabase($this->getDatabaseName());
diff --git a/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php b/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
index 1c0efb058..d1c437745 100644
--- a/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
+++ b/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
@@ -17,7 +17,6 @@
 use function file_get_contents;
 use function get_debug_type;
 use function is_int;
-use function version_compare;
 
 /**
  * Prose test 22: Range Explicit Encryption
@@ -41,9 +40,7 @@ public function setUp(): void
             $this->markTestSkipped('Range explicit encryption tests require replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
-            $this->markTestSkipped('Range explicit encryption tests require MongoDB 7.0 or later');
-        }
+        $this->skipIfServerVersion('<', '7.0.0', 'Range explicit encryption tests require MongoDB 7.0 or later');
 
         $client = static::createTestClient();
 
diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index 744156fe1..e75ef306d 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -46,7 +46,6 @@
 use function strlen;
 use function substr;
 use function unserialize;
-use function version_compare;
 
 use const DIRECTORY_SEPARATOR;
 use const PATH_SEPARATOR;
@@ -1339,9 +1338,7 @@ public function testExplicitEncryption(Closure $test): void
             $this->markTestSkipped('Explicit encryption tests require replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '7.0.0', '<')) {
-            $this->markTestSkipped('Explicit encryption tests require MongoDB 7.0 or later');
-        }
+        $this->skipIfServerVersion('<', '7.0.0', 'Explicit encryption tests require MongoDB 7.0 or later');
 
         // Test setup
         $encryptedFields = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/encryptedFields.json'));
diff --git a/tests/SpecTests/RetryableWritesSpecTest.php b/tests/SpecTests/RetryableWritesSpecTest.php
index 4479d9806..a0506cadc 100644
--- a/tests/SpecTests/RetryableWritesSpecTest.php
+++ b/tests/SpecTests/RetryableWritesSpecTest.php
@@ -12,7 +12,6 @@
 use function basename;
 use function file_get_contents;
 use function glob;
-use function version_compare;
 
 /**
  * Retryable writes spec tests.
@@ -90,9 +89,7 @@ public function testNoWritesPerformedErrorReturnsOriginalError(): void
             $this->markTestSkipped('Test only applies to replica sets');
         }
 
-        if (version_compare($this->getServerVersion(), '4.4.0', '<')) {
-            $this->markTestSkipped('NoWritesPerformed error label is only supported on MongoDB 4.4+');
-        }
+        $this->skipIfServerVersion('<', '4.4.0', 'NoWritesPerformed error label is only supported on MongoDB 4.4+');
 
         $client = self::createTestClient(null, ['retryWrites' => true]);
 

From eb2a813abdc1e00a46c7cbf703ed9cbce490d084 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Wed, 21 Jun 2023 18:55:07 +0200
Subject: [PATCH 318/321] PHPLIB-1158: Upgrade psalm+rector job to PHP 8.2
 (#1113)

---
 .github/workflows/coding-standards.yml |  4 ++--
 .github/workflows/static-analysis.yml  |  4 ++--
 psalm-baseline.xml                     | 25 ++++++-------------------
 3 files changed, 10 insertions(+), 23 deletions(-)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index a61635ef0..284b3ce21 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -19,12 +19,12 @@ on:
 jobs:
   phpcs:
     name: "phpcs"
-    runs-on: "ubuntu-20.04"
+    runs-on: "ubuntu-22.04"
 
     strategy:
       matrix:
         php-version:
-          - "7.4"
+          - "8.2"
         driver-version:
           - "mongodb/mongo-php-driver@master"
 
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 5b0840407..33bdd15c9 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -19,12 +19,12 @@ on:
 jobs:
   psalm:
     name: "Psalm"
-    runs-on: "ubuntu-20.04"
+    runs-on: "ubuntu-22.04"
 
     strategy:
       matrix:
         php-version:
-          - "7.4"
+          - "8.2"
         driver-version:
           - "mongodb/mongo-php-driver@master"
 
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index b9f153751..778b248ae 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -41,9 +41,8 @@
     
   
   
-    
+    
       new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, get_debug_type($value)))
-      new static('Expected update operator(s) or non-empty pipeline for ' . $name)
     
   
   
@@ -421,18 +420,13 @@
       $options['pipeline']
       $this->options['typeMap']
     
-    
+    
       $cmd[$option]
-      $i
       $options['session']
       $options['writeConcern']
     
   
   
-    
-      ! is_array($encryptedFields['fields'])
-      ! is_array($field) && ! is_object($field)
-    
     
       $this->options['encryptedFields']
     
@@ -555,8 +549,7 @@
     
       $options['modifiers'][$modifier[1]]
     
-    
-      $cmd['readConcern']
+    
       $options[$modifier[0]]
       $options[$option]
       $options['readPreference']
@@ -712,9 +705,8 @@
     
       $this->options['writeConcern']
     
-    
+    
       $cmd['bypassDocumentValidation']
-      $cmd['writeConcern']
       $options[$option]
       $options['session']
       $options['writeConcern']
@@ -799,18 +791,13 @@
       $typeMap['fieldPaths'][$fieldPath]
       $value
     
-    
-      array|object
+    
       array|object|null
       array|object|null
     
-    
-      $type
-    
-    
+    
       $collectionInfo['options']['encryptedFields'] ?? null
       $encryptedFieldsMap[$databaseName . '.' . $collectionName] ?? null
-      toPHP(fromPHP($document), $typeMap)
     
   
 

From fe47d48540813f2b7c56975501990c797bcdf118 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Thu, 22 Jun 2023 08:50:04 +0200
Subject: [PATCH 319/321] PHPLIB-1147, PHPLIB-1148: Int64 improvements (#1112)

* PHPLIB-1147: Create Int64 instances directly

* PHPLIB-1148: Add comparator for Int64 objects

* Simplify comparison of Int64
---
 phpunit.evergreen.xml                         |   2 +-
 phpunit.xml.dist                              |   2 +-
 tests/Comparator/Int64Comparator.php          |  45 ++++
 tests/Comparator/Int64ComparatorTest.php      | 211 ++++++++++++++++++
 .../FunctionalTestCase.php                    |  11 -
 .../Prose22_RangeExplicitEncryptionTest.php   |   7 +-
 .../ClientSideEncryptionSpecTest.php          |  14 +-
 tests/SpecTests/DocumentsMatchConstraint.php  |   8 -
 .../DocumentsMatchConstraintTest.php          |   6 +-
 .../Constraint/IsBsonTypeTest.php             |   6 +-
 tests/UnifiedSpecTests/Constraint/Matches.php |  13 --
 tests/bootstrap.php                           |   9 +
 12 files changed, 279 insertions(+), 55 deletions(-)
 create mode 100644 tests/Comparator/Int64Comparator.php
 create mode 100644 tests/Comparator/Int64ComparatorTest.php
 create mode 100644 tests/bootstrap.php

diff --git a/phpunit.evergreen.xml b/phpunit.evergreen.xml
index da26eba50..56b35f6f8 100644
--- a/phpunit.evergreen.xml
+++ b/phpunit.evergreen.xml
@@ -6,7 +6,7 @@
          beStrictAboutOutputDuringTests="true"
          beStrictAboutChangesToGlobalState="true"
          colors="true"
-         bootstrap="vendor/autoload.php"
+         bootstrap="tests/bootstrap.php"
          defaultTestSuite="Default Test Suite"
 >
 
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index f8a13387c..c4f6cb2b7 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -6,7 +6,7 @@
          beStrictAboutOutputDuringTests="true"
          beStrictAboutChangesToGlobalState="true"
          colors="true"
-         bootstrap="vendor/autoload.php"
+         bootstrap="tests/bootstrap.php"
          defaultTestSuite="Default Test Suite"
 >
 
diff --git a/tests/Comparator/Int64Comparator.php b/tests/Comparator/Int64Comparator.php
new file mode 100644
index 000000000..c985e0c03
--- /dev/null
+++ b/tests/Comparator/Int64Comparator.php
@@ -0,0 +1,45 @@
+isComparable($actual))
+            || ($actual instanceof Int64 && $this->isComparable($expected));
+    }
+
+    public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false): void
+    {
+        if ($expected == $actual) {
+            return;
+        }
+
+        throw new ComparisonFailure(
+            $expected,
+            $actual,
+            '',
+            '',
+            false,
+            sprintf(
+                'Failed asserting that %s matches expected %s.',
+                $this->exporter->export($actual),
+                $this->exporter->export($expected)
+            )
+        );
+    }
+
+    private function isComparable($value): bool
+    {
+        return $value instanceof Int64 || is_numeric($value);
+    }
+}
diff --git a/tests/Comparator/Int64ComparatorTest.php b/tests/Comparator/Int64ComparatorTest.php
new file mode 100644
index 000000000..9a887acd3
--- /dev/null
+++ b/tests/Comparator/Int64ComparatorTest.php
@@ -0,0 +1,211 @@
+assertSame($expectedResult, (new Int64Comparator())->accepts($expectedValue, $actualValue));
+    }
+
+    public static function provideAcceptsValues(): Generator
+    {
+        yield 'Expects Int64, Actual Int64' => [
+            'expectedResult' => true,
+            'expectedValue' => new Int64(123),
+            'actualValue' => new Int64(123),
+        ];
+
+        yield 'Expects Int64, Actual int' => [
+            'expectedResult' => true,
+            'expectedValue' => new Int64(123),
+            'actualValue' => 123,
+        ];
+
+        yield 'Expects Int64, Actual int string' => [
+            'expectedResult' => true,
+            'expectedValue' => new Int64(123),
+            'actualValue' => '123',
+        ];
+
+        yield 'Expects Int64, Actual float' => [
+            'expectedResult' => true,
+            'expectedValue' => new Int64(123),
+            'actualValue' => 123.0,
+        ];
+
+        yield 'Expects Int64, Actual float string' => [
+            'expectedResult' => true,
+            'expectedValue' => new Int64(123),
+            'actualValue' => '123.0',
+        ];
+
+        yield 'Expects Int64, Actual non-numeric string' => [
+            'expectedResult' => false,
+            'expectedValue' => new Int64(123),
+            'actualValue' => 'foo',
+        ];
+
+        yield 'Expects int, Actual Int64' => [
+            'expectedResult' => true,
+            'expectedValue' => 123,
+            'actualValue' => new Int64(123),
+        ];
+
+        yield 'Expects int string, Actual Int64' => [
+            'expectedResult' => true,
+            'expectedValue' => '123',
+            'actualValue' => new Int64(123),
+        ];
+
+        yield 'Expects float, Actual Int64' => [
+            'expectedResult' => true,
+            'expectedValue' => 123.0,
+            'actualValue' => new Int64(123),
+        ];
+
+        yield 'Expects float string, Actual Int64' => [
+            'expectedResult' => true,
+            'expectedValue' => '123.0',
+            'actualValue' => new Int64(123),
+        ];
+
+        yield 'Expects non-numeric string, Actual Int64' => [
+            'expectedResult' => false,
+            'expectedValue' => 'foo',
+            'actualValue' => new Int64(123),
+        ];
+
+        yield 'Expects float, Actual float' => [
+            'expectedResult' => false,
+            'expectedValue' => 123.0,
+            'actualValue' => 123.0,
+        ];
+
+        yield 'Expects numeric string, Actual numeric string' => [
+            'expectedResult' => false,
+            'expectedValue' => '123',
+            'actualValue' => '123',
+        ];
+    }
+
+    /**
+     * @dataProvider provideMatchingAssertions
+     * @doesNotPerformAssertions
+     */
+    public function testMatchingAssertions($expected, $actual): void
+    {
+        (new Int64Comparator())->assertEquals($expected, $actual);
+    }
+
+    public static function provideMatchingAssertions(): Generator
+    {
+        yield 'Expected Int64, Actual Int64' => [
+            'expected' => new Int64(8589934592),
+            'actual' => new Int64(8589934592),
+        ];
+
+        yield 'Expected Int64, Actual int' => [
+            'expected' => new Int64(8589934592),
+            'actual' => 8589934592,
+        ];
+
+        yield 'Expected Int64, Actual int string' => [
+            'expected' => new Int64(8589934592),
+            'actual' => '8589934592',
+        ];
+
+        yield 'Expected Int64, Actual float' => [
+            'expected' => new Int64(8589934592),
+            'actual' => 8589934592.0,
+        ];
+
+        yield 'Expected Int64, Actual float string' => [
+            'expected' => new Int64(8589934592),
+            'actual' => '8589934592.0',
+        ];
+
+        yield 'Expected int, Actual Int64' => [
+            'expected' => 8589934592,
+            'actual' => new Int64(8589934592),
+        ];
+
+        yield 'Expected int string, Actual Int64' => [
+            'expected' => '8589934592',
+            'actual' => new Int64(8589934592),
+        ];
+
+        yield 'Expected float, Actual Int64' => [
+            'expected' => 8589934592.0,
+            'actual' => new Int64(8589934592),
+        ];
+
+        yield 'Expected float string, Actual Int64' => [
+            'expected' => '8589934592.0',
+            'actual' => new Int64(8589934592),
+        ];
+    }
+
+    /** @dataProvider provideFailingValues */
+    public function testFailingAssertions($expected, $actual): void
+    {
+        $this->expectException(ComparisonFailure::class);
+
+        (new Int64Comparator())->assertEquals($expected, $actual);
+    }
+
+    public static function provideFailingValues(): Generator
+    {
+        yield 'Expected Int64, Actual Int64' => [
+            'expected' => new Int64(8589934592),
+            'actual' => new Int64(456),
+        ];
+
+        yield 'Expected Int64, Actual int' => [
+            'expected' => new Int64(8589934592),
+            'actual' => 456,
+        ];
+
+        yield 'Expected Int64, Actual int string' => [
+            'expected' => new Int64(8589934592),
+            'actual' => '456',
+        ];
+
+        yield 'Expected Int64, Actual float' => [
+            'expected' => new Int64(8589934592),
+            'actual' => 8589934592.1,
+        ];
+
+        yield 'Expected Int64, Actual float string' => [
+            'expected' => new Int64(8589934592),
+            'actual' => '8589934592.1',
+        ];
+
+        yield 'Expected int, Actual Int64' => [
+            'expected' => 8589934592,
+            'actual' => new Int64(456),
+        ];
+
+        yield 'Expected int string, Actual Int64' => [
+            'expected' => '8589934592',
+            'actual' => new Int64(456),
+        ];
+
+        yield 'Expected float, Actual Int64' => [
+            'expected' => 8589934592.1,
+            'actual' => new Int64(456),
+        ];
+
+        yield 'Expected float string, Actual Int64' => [
+            'expected' => '8589934592.1',
+            'actual' => new Int64(456),
+        ];
+    }
+}
diff --git a/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php b/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
index 08368b0ac..a48ea03ad 100644
--- a/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
+++ b/tests/SpecTests/ClientSideEncryption/FunctionalTestCase.php
@@ -2,7 +2,6 @@
 
 namespace MongoDB\Tests\SpecTests\ClientSideEncryption;
 
-use MongoDB\BSON\Int64;
 use MongoDB\Client;
 use MongoDB\Driver\WriteConcern;
 use MongoDB\Tests\SpecTests\FunctionalTestCase as BaseFunctionalTestCase;
@@ -14,8 +13,6 @@
 use function is_executable;
 use function is_readable;
 use function sprintf;
-use function strlen;
-use function unserialize;
 
 use const DIRECTORY_SEPARATOR;
 use const PATH_SEPARATOR;
@@ -69,14 +66,6 @@ protected static function insertKeyVaultData(Client $client, ?array $keyVaultDat
         $collection->insertMany($keyVaultData);
     }
 
-    protected static function createInt64(string $value): Int64
-    {
-        $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value);
-        $int64 = sprintf('C:%d:"%s":%d:{%s}', strlen(Int64::class), Int64::class, strlen($array), $array);
-
-        return unserialize($int64);
-    }
-
     private function createTestCollection(?stdClass $encryptedFields = null, ?stdClass $jsonSchema = null): void
     {
         $context = $this->getContext();
diff --git a/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php b/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
index d1c437745..46de1c49f 100644
--- a/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
+++ b/tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php
@@ -8,6 +8,7 @@
 use MongoDB\BSON\Binary;
 use MongoDB\BSON\Decimal128;
 use MongoDB\BSON\Document;
+use MongoDB\BSON\Int64;
 use MongoDB\BSON\UTCDateTime;
 use MongoDB\Driver\ClientEncryption;
 use MongoDB\Driver\Exception\EncryptionException;
@@ -168,8 +169,8 @@ public static function provideTypeAndRangeOpts(): Generator
         yield 'Long' => [
             'Long',
             [
-                'min' => self::createInt64('0'),
-                'max' => self::createInt64('200'),
+                'min' => new Int64(0),
+                'max' => new Int64(200),
                 'sparsity' => 1,
             ],
         ];
@@ -467,7 +468,7 @@ private static function getCastCallableForType(string $type): callable
 
             case 'Long':
                 return function (int $value) {
-                    return self::createInt64((string) $value);
+                    return new Int64($value);
                 };
 
             default:
diff --git a/tests/SpecTests/ClientSideEncryptionSpecTest.php b/tests/SpecTests/ClientSideEncryptionSpecTest.php
index e75ef306d..6d30a526e 100644
--- a/tests/SpecTests/ClientSideEncryptionSpecTest.php
+++ b/tests/SpecTests/ClientSideEncryptionSpecTest.php
@@ -43,9 +43,7 @@
 use function json_decode;
 use function sprintf;
 use function str_repeat;
-use function strlen;
 use function substr;
-use function unserialize;
 
 use const DIRECTORY_SEPARATOR;
 use const PATH_SEPARATOR;
@@ -1862,14 +1860,6 @@ public static function provideRewrapManyDataKeySrcAndDstProviders()
         }
     }
 
-    private function createInt64(string $value): Int64
-    {
-        $array = sprintf('a:1:{s:7:"integer";s:%d:"%s";}', strlen($value), $value);
-        $int64 = sprintf('C:%d:"%s":%d:{%s}', strlen(Int64::class), Int64::class, strlen($array), $array);
-
-        return unserialize($int64);
-    }
-
     private function createTestCollection(?stdClass $encryptedFields = null, ?stdClass $jsonSchema = null): void
     {
         $context = $this->getContext();
@@ -1936,7 +1926,7 @@ private function encryptCorpusValue(string $fieldName, stdClass $data, ClientEnc
                 /* Note: workaround issue where mongocryptd refuses to encrypt
                  * 32-bit integers if schemaMap defines a "long" BSON type. */
                 $value = $data->type === 'long' && ! $data->value instanceof Int64
-                    ? $this->createInt64($data->value)
+                    ? new Int64($data->value)
                     : $data->value;
 
                 $encrypted = $clientEncryption->encrypt($value, $encryptionOptions);
@@ -1987,7 +1977,7 @@ private function prepareCorpusData(string $fieldName, stdClass $data, ClientEncr
             /* Note: workaround issue where mongocryptd refuses to encrypt
              * 32-bit integers if schemaMap defines a "long" BSON type. */
             if ($data->type === 'long' && ! $data->value instanceof Int64) {
-                $data->value = $this->createInt64($data->value);
+                $data->value = new Int64($data->value);
             }
 
             return $data;
diff --git a/tests/SpecTests/DocumentsMatchConstraint.php b/tests/SpecTests/DocumentsMatchConstraint.php
index 3dde8e705..cf5f98ee7 100644
--- a/tests/SpecTests/DocumentsMatchConstraint.php
+++ b/tests/SpecTests/DocumentsMatchConstraint.php
@@ -30,8 +30,6 @@
 use function PHPUnit\Framework\logicalOr;
 use function sprintf;
 
-use const PHP_INT_SIZE;
-
 /**
  * Constraint that checks if one document matches another.
  *
@@ -308,12 +306,6 @@ private function prepareBSON($bson, bool $isRoot, bool $sortKeys = false)
                 $bson[$key] = $this->prepareBSON($value, false, $sortKeys);
                 continue;
             }
-
-            /* Convert Int64 objects to integers on 64-bit platforms for
-             * compatibility reasons. */
-            if ($value instanceof Int64 && PHP_INT_SIZE != 4) {
-                $bson[$key] = (int) ((string) $value);
-            }
         }
 
         return $bson;
diff --git a/tests/SpecTests/DocumentsMatchConstraintTest.php b/tests/SpecTests/DocumentsMatchConstraintTest.php
index bd61a9354..c14f001c6 100644
--- a/tests/SpecTests/DocumentsMatchConstraintTest.php
+++ b/tests/SpecTests/DocumentsMatchConstraintTest.php
@@ -4,6 +4,7 @@
 
 use MongoDB\BSON\Binary;
 use MongoDB\BSON\Decimal128;
+use MongoDB\BSON\Int64;
 use MongoDB\BSON\Javascript;
 use MongoDB\BSON\MaxKey;
 use MongoDB\BSON\MinKey;
@@ -18,7 +19,6 @@
 
 use function MongoDB\BSON\fromJSON;
 use function MongoDB\BSON\toPHP;
-use function unserialize;
 
 use const PHP_INT_SIZE;
 
@@ -85,8 +85,8 @@ public function provideBSONTypes()
         $undefined = toPHP(fromJSON('{ "x": {"$undefined": true} }'))->x;
         $symbol = toPHP(fromJSON('{ "x": {"$symbol": "test"} }'))->x;
         $dbPointer = toPHP(fromJSON('{ "x": {"$dbPointer": {"$ref": "db.coll", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" }  }} }'))->x;
-        $int64 = unserialize('C:18:"MongoDB\BSON\Int64":28:{a:1:{s:7:"integer";s:1:"1";}}');
-        $long = PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296;
+        $int64 = new Int64(1);
+        $long = PHP_INT_SIZE == 4 ? new Int64('4294967296') : 4294967296;
 
         return [
             'double' => ['double', 1.4],
diff --git a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
index 6bace1633..d14b09e60 100644
--- a/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
+++ b/tests/UnifiedSpecTests/Constraint/IsBsonTypeTest.php
@@ -4,6 +4,7 @@
 
 use MongoDB\BSON\Binary;
 use MongoDB\BSON\Decimal128;
+use MongoDB\BSON\Int64;
 use MongoDB\BSON\Javascript;
 use MongoDB\BSON\MaxKey;
 use MongoDB\BSON\MinKey;
@@ -22,7 +23,6 @@
 use function fopen;
 use function MongoDB\BSON\fromJSON;
 use function MongoDB\BSON\toPHP;
-use function unserialize;
 
 use const PHP_INT_SIZE;
 
@@ -39,8 +39,8 @@ public function provideTypes()
         $undefined = toPHP(fromJSON('{ "x": {"$undefined": true} }'))->x;
         $symbol = toPHP(fromJSON('{ "x": {"$symbol": "test"} }'))->x;
         $dbPointer = toPHP(fromJSON('{ "x": {"$dbPointer": {"$ref": "db.coll", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" }  }} }'))->x;
-        $int64 = unserialize('C:18:"MongoDB\BSON\Int64":28:{a:1:{s:7:"integer";s:1:"1";}}');
-        $long = PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296;
+        $int64 = new Int64(1);
+        $long = PHP_INT_SIZE == 4 ? new Int64('4294967296') : 4294967296;
 
         return [
             'double' => ['double', 1.4],
diff --git a/tests/UnifiedSpecTests/Constraint/Matches.php b/tests/UnifiedSpecTests/Constraint/Matches.php
index 579240d69..4f1586625 100644
--- a/tests/UnifiedSpecTests/Constraint/Matches.php
+++ b/tests/UnifiedSpecTests/Constraint/Matches.php
@@ -40,8 +40,6 @@
 use function strpos;
 use function strrchr;
 
-use const PHP_INT_SIZE;
-
 /**
  * Constraint that checks if one value matches another.
  *
@@ -425,17 +423,6 @@ private static function prepare($bson)
             return $bson;
         }
 
-        /* Convert Int64 objects to integers on 64-bit platforms for
-         * compatibility reasons. */
-        if ($bson instanceof Int64 && PHP_INT_SIZE != 4) {
-            return (int) ((string) $bson);
-        }
-
-        /* TODO: Convert Int64 objects to integers on 32-bit platforms if they
-         * can be expressed as such. This is necessary to handle flexible
-         * numeric comparisons if the server returns 32-bit value as a 64-bit
-         * integer (e.g. cursor ID). */
-
         // Serializable can produce an array or object, so recurse on its output
         if ($bson instanceof Serializable) {
             return self::prepare($bson->bsonSerialize());
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 000000000..d10cd460d
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,9 @@
+register(new Int64Comparator());

From 38c48c1748de8a473ca4200acc9c21ec78a72a77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?=
 
Date: Thu, 22 Jun 2023 12:20:24 +0200
Subject: [PATCH 320/321] Test against ext-mongodb 1.16.0 (#1114)

https://github.com/mongodb/mongo-php-driver/releases/tag/1.16.0
---
 .evergreen/config.yml                  |  8 +++-----
 .github/workflows/coding-standards.yml |  2 +-
 .github/workflows/static-analysis.yml  |  2 +-
 .github/workflows/tests.yml            | 12 ++++++------
 4 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/.evergreen/config.yml b/.evergreen/config.yml
index 134e5c005..90b07afec 100644
--- a/.evergreen/config.yml
+++ b/.evergreen/config.yml
@@ -760,15 +760,13 @@ axes:
       - id: "oldest-supported"
         display_name: "PHPC 1.16.0"
         variables:
-          EXTENSION_BRANCH: "master"
-#          EXTENSION_VERSION: "1.16.0"
+          EXTENSION_VERSION: "1.16.0"
       - id: "latest-stable"
         display_name: "PHPC (1.16.x)"
         variables:
-          EXTENSION_BRANCH: "master"
-#          EXTENSION_VERSION: "stable"
+          EXTENSION_VERSION: "stable"
       - id: "latest-dev"
-        display_name: "PHPC (1.16-dev)"
+        display_name: "PHPC (1.17-dev)"
         variables:
           EXTENSION_BRANCH: "master"
 
diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index 284b3ce21..c271d72fa 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -26,7 +26,7 @@ jobs:
         php-version:
           - "8.2"
         driver-version:
-          - "mongodb/mongo-php-driver@master"
+          - "stable"
 
     steps:
       - name: "Checkout"
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index 33bdd15c9..ec312c700 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -26,7 +26,7 @@ jobs:
         php-version:
           - "8.2"
         driver-version:
-          - "mongodb/mongo-php-driver@master"
+          - "stable"
 
     steps:
       - name: "Checkout"
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 061ecc852..9ce0c8b91 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -34,34 +34,34 @@ jobs:
         mongodb-version:
           - "4.4"
         driver-version:
-          - "mongodb/mongo-php-driver@master"
+          - "stable"
         topology:
           - "server"
         include:
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "6.0"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "replica_set"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "6.0"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "sharded_cluster"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "5.0"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "server"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "4.4"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "replica_set"
           - os: "ubuntu-20.04"
             php-version: "8.0"
             mongodb-version: "4.4"
-            driver-version: "mongodb/mongo-php-driver@master"
+            driver-version: "stable"
             topology: "sharded_cluster"
 
     steps:

From d4cdf057a67cb99a32db8984a16959bfa7ca7eb5 Mon Sep 17 00:00:00 2001
From: Andreas Braun 
Date: Thu, 22 Jun 2023 13:04:04 +0200
Subject: [PATCH 321/321] Refactor psalm and phpcs workflows to get static
 names (#1115)

Using a matrix strategy results in changing names whenever we change the driver or PHP version, requiring an update to protected branch settings. Moving this configuration to env variables prevents this issue.
---
 .github/workflows/coding-standards.yml | 19 ++++++++-----------
 .github/workflows/static-analysis.yml  | 19 ++++++++-----------
 2 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index c271d72fa..c3e8d5d49 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -16,18 +16,15 @@ on:
     paths-ignore:
       - "docs/**"
 
+env:
+  PHP_VERSION: "8.2"
+  DRIVER_VERSION: "stable"
+
 jobs:
   phpcs:
     name: "phpcs"
     runs-on: "ubuntu-22.04"
 
-    strategy:
-      matrix:
-        php-version:
-          - "8.2"
-        driver-version:
-          - "stable"
-
     steps:
       - name: "Checkout"
         uses: "actions/checkout@v3"
@@ -36,8 +33,8 @@ jobs:
         id: extcache
         uses: shivammathur/cache-extensions@v1
         with:
-          php-version: ${{ matrix.php-version }}
-          extensions: "mongodb-${{ matrix.driver-version }}"
+          php-version: ${{ env.PHP_VERSION }}
+          extensions: "mongodb-${{ env.DRIVER_VERSION }}"
           key: "extcache-v1"
 
       - name: Cache extensions
@@ -51,8 +48,8 @@ jobs:
         uses: "shivammathur/setup-php@v2"
         with:
           coverage: "none"
-          extensions: "mongodb-${{ matrix.driver-version }}"
-          php-version: "${{ matrix.php-version }}"
+          extensions: "mongodb-${{ env.DRIVER_VERSION }}"
+          php-version: "${{ env.PHP_VERSION }}"
           tools: "cs2pr"
 
       - name: "Show driver information"
diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml
index ec312c700..8f9c45019 100644
--- a/.github/workflows/static-analysis.yml
+++ b/.github/workflows/static-analysis.yml
@@ -16,18 +16,15 @@ on:
     paths-ignore:
       - "docs/**"
 
+env:
+  PHP_VERSION: "8.2"
+  DRIVER_VERSION: "stable"
+
 jobs:
   psalm:
     name: "Psalm"
     runs-on: "ubuntu-22.04"
 
-    strategy:
-      matrix:
-        php-version:
-          - "8.2"
-        driver-version:
-          - "stable"
-
     steps:
       - name: "Checkout"
         uses: "actions/checkout@v3"
@@ -36,8 +33,8 @@ jobs:
         id: extcache
         uses: shivammathur/cache-extensions@v1
         with:
-          php-version: ${{ matrix.php-version }}
-          extensions: "mongodb-${{ matrix.driver-version }}"
+          php-version: ${{ env.PHP_VERSION }}
+          extensions: "mongodb-${{ ENV.DRIVER_VERSION }}"
           key: "extcache-v1"
 
       - name: Cache extensions
@@ -51,8 +48,8 @@ jobs:
         uses: "shivammathur/setup-php@v2"
         with:
           coverage: "none"
-          extensions: "mongodb-${{ matrix.driver-version }}"
-          php-version: "${{ matrix.php-version }}"
+          extensions: "mongodb-${{ ENV.DRIVER_VERSION }}"
+          php-version: "${{ env.PHP_VERSION }}"
           tools: "cs2pr"
 
       - name: "Show driver information"