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": [