From d405fa4bd7bba84bc3662fd78e77eace4638a4cb Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 8 Mar 2024 16:50:44 -0500 Subject: [PATCH 1/2] PHPLIB-1408: Convert ADL spec test to unified test format Synced with mongodb/specifications#1545 Moves isAtlasDataLake() function to FunctionalTestCase, since it is now shared across test files. Fixes typo in ADL prose test comment. --- tests/FunctionalTestCase.php | 10 ++ tests/SpecTests/AtlasDataLakeSpecTest.php | 113 +----------------- .../SpecTests/atlas_data_lake/aggregate.json | 53 -------- .../estimatedDocumentCount.json | 27 ----- tests/SpecTests/atlas_data_lake/getMore.json | 57 --------- .../atlas_data_lake/listCollections.json | 25 ---- .../atlas_data_lake/listDatabases.json | 24 ---- .../SpecTests/atlas_data_lake/runCommand.json | 31 ----- tests/UnifiedSpecTests/UnifiedSpecTest.php | 18 +++ .../atlas-data-lake/aggregate.json | 84 +++++++++++++ .../estimatedDocumentCount.json | 56 +++++++++ .../atlas-data-lake}/find.json | 49 ++++++-- .../atlas-data-lake/getMore.json | 95 +++++++++++++++ .../atlas-data-lake/listCollections.json | 48 ++++++++ .../atlas-data-lake/listDatabases.json | 41 +++++++ .../atlas-data-lake/runCommand.json | 54 +++++++++ 16 files changed, 447 insertions(+), 338 deletions(-) delete mode 100644 tests/SpecTests/atlas_data_lake/aggregate.json delete mode 100644 tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json delete mode 100644 tests/SpecTests/atlas_data_lake/getMore.json delete mode 100644 tests/SpecTests/atlas_data_lake/listCollections.json delete mode 100644 tests/SpecTests/atlas_data_lake/listDatabases.json delete mode 100644 tests/SpecTests/atlas_data_lake/runCommand.json create mode 100644 tests/UnifiedSpecTests/atlas-data-lake/aggregate.json create mode 100644 tests/UnifiedSpecTests/atlas-data-lake/estimatedDocumentCount.json rename tests/{SpecTests/atlas_data_lake => UnifiedSpecTests/atlas-data-lake}/find.json (52%) create mode 100644 tests/UnifiedSpecTests/atlas-data-lake/getMore.json create mode 100644 tests/UnifiedSpecTests/atlas-data-lake/listCollections.json create mode 100644 tests/UnifiedSpecTests/atlas-data-lake/listDatabases.json create mode 100644 tests/UnifiedSpecTests/atlas-data-lake/runCommand.json diff --git a/tests/FunctionalTestCase.php b/tests/FunctionalTestCase.php index c45a94367..53d1c3558 100644 --- a/tests/FunctionalTestCase.php +++ b/tests/FunctionalTestCase.php @@ -522,6 +522,16 @@ protected function skipIfTransactionsAreNotSupported(): void } } + protected function isAtlasDataLake(): bool + { + $buildInfo = $this->getPrimaryServer()->executeCommand( + $this->getDatabaseName(), + new Command(['buildInfo' => 1]), + )->toArray()[0]; + + return ! empty($buildInfo->dataLake); + } + protected function isEnterprise(): bool { $buildInfo = $this->getPrimaryServer()->executeCommand( diff --git a/tests/SpecTests/AtlasDataLakeSpecTest.php b/tests/SpecTests/AtlasDataLakeSpecTest.php index 5fd10ce74..15f45434c 100644 --- a/tests/SpecTests/AtlasDataLakeSpecTest.php +++ b/tests/SpecTests/AtlasDataLakeSpecTest.php @@ -2,16 +2,11 @@ namespace MongoDB\Tests\SpecTests; -use MongoDB\Driver\Command; use MongoDB\Driver\Cursor; use MongoDB\Tests\CommandObserver; -use stdClass; -use function basename; use function current; use function explode; -use function file_get_contents; -use function glob; use function parse_url; /** @@ -32,101 +27,7 @@ public function setUp(): void } /** - * Assert that the expected and actual command documents match. - * - * @param stdClass $expected Expected command document - * @param stdClass $actual Actual command document - */ - public static function assertCommandMatches(stdClass $expected, stdClass $actual): void - { - foreach ($expected as $key => $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 testAtlasDataLake(stdClass $test, ?array $runOn, array $data, ?string $databaseName = null, ?string $collectionName = null): void - { - if (isset($runOn)) { - $this->checkServerRequirements($runOn); - } - - if (isset($test->skipReason)) { - $this->markTestSkipped($test->skipReason); - } - - $databaseName ??= $this->getDatabaseName(); - $collectionName ??= $this->getCollectionName(); - - $context = Context::fromCrud($test, $databaseName, $collectionName); - $this->setContext($context); - - /* Note: Atlas Data Lake is read-only, so do not attempt to drop the - * collection under test or insert data fixtures. Necesarry data - * fixtures are already specified in the mongohoused configuration. */ - - if (isset($test->failPoint)) { - throw new LogicException('ADL tests are not expected to configure fail points'); - } - - if (isset($test->expectations)) { - $commandExpectations = CommandExpectations::fromCrud($context->getClient(), (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)) { - throw new LogicException('ADL tests are not expected to assert collection data'); - } - } - - public function provideTests() - { - $testArgs = []; - - foreach (glob(__DIR__ . '/atlas_data_lake/*.json') as $filename) { - $json = $this->decodeJson(file_get_contents($filename)); - $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; - $testArgs[$name] = [$test, $runOn, $data, $databaseName, $collectionName]; - } - } - - return $testArgs; - } - - /** - * Prose test 1: Connect without authentication + * Prose test 1: killCursors command */ public function testKillCursors(): void { @@ -235,16 +136,4 @@ public function testConnectwithSCRAMSHA256(): void $this->assertInstanceOf(Cursor::class, $cursor); $this->assertCommandSucceeded(current($cursor->toArray())); } - - private function isAtlasDataLake(): bool - { - $cursor = $this->manager->executeCommand( - $this->getDatabaseName(), - new Command(['buildInfo' => 1]), - ); - - $document = current($cursor->toArray()); - - return ! empty($document->dataLake); - } } diff --git a/tests/SpecTests/atlas_data_lake/aggregate.json b/tests/SpecTests/atlas_data_lake/aggregate.json deleted file mode 100644 index 99995bca4..000000000 --- a/tests/SpecTests/atlas_data_lake/aggregate.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "collection_name": "driverdata", - "database_name": "test", - "tests": [ - { - "description": "Aggregate with pipeline (project, sort, limit)", - "operations": [ - { - "object": "collection", - "name": "aggregate", - "arguments": { - "pipeline": [ - { - "$project": { - "_id": 0 - } - }, - { - "$sort": { - "a": 1 - } - }, - { - "$limit": 2 - } - ] - }, - "result": [ - { - "a": 1, - "b": 2, - "c": 3 - }, - { - "a": 2, - "b": 3, - "c": 4 - } - ] - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "aggregate": "driverdata" - } - } - } - ] - } - ] -} diff --git a/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json b/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json deleted file mode 100644 index 997a3ab3f..000000000 --- a/tests/SpecTests/atlas_data_lake/estimatedDocumentCount.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "collection_name": "driverdata", - "database_name": "test", - "tests": [ - { - "description": "estimatedDocumentCount succeeds", - "operations": [ - { - "object": "collection", - "name": "estimatedDocumentCount", - "result": 15 - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "count": "driverdata" - }, - "command_name": "count", - "database_name": "test" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/atlas_data_lake/getMore.json b/tests/SpecTests/atlas_data_lake/getMore.json deleted file mode 100644 index e2e1d4788..000000000 --- a/tests/SpecTests/atlas_data_lake/getMore.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "collection_name": "driverdata", - "database_name": "test", - "tests": [ - { - "description": "A successful find event with getMore", - "operations": [ - { - "object": "collection", - "name": "find", - "arguments": { - "filter": { - "a": { - "$gte": 2 - } - }, - "sort": { - "a": 1 - }, - "batchSize": 3, - "limit": 4 - } - } - ], - "expectations": [ - { - "command_started_event": { - "command": { - "find": "driverdata", - "filter": { - "a": { - "$gte": 2 - } - }, - "sort": { - "a": 1 - }, - "batchSize": 3, - "limit": 4 - }, - "command_name": "find", - "database_name": "test" - } - }, - { - "command_started_event": { - "command": { - "batchSize": 1 - }, - "command_name": "getMore", - "database_name": "cursors" - } - } - ] - } - ] -} diff --git a/tests/SpecTests/atlas_data_lake/listCollections.json b/tests/SpecTests/atlas_data_lake/listCollections.json deleted file mode 100644 index e419f7b3e..000000000 --- a/tests/SpecTests/atlas_data_lake/listCollections.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "database_name": "test", - "tests": [ - { - "description": "ListCollections succeeds", - "operations": [ - { - "name": "listCollections", - "object": "database" - } - ], - "expectations": [ - { - "command_started_event": { - "command_name": "listCollections", - "database_name": "test", - "command": { - "listCollections": 1 - } - } - } - ] - } - ] -} diff --git a/tests/SpecTests/atlas_data_lake/listDatabases.json b/tests/SpecTests/atlas_data_lake/listDatabases.json deleted file mode 100644 index 6458148e4..000000000 --- a/tests/SpecTests/atlas_data_lake/listDatabases.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "tests": [ - { - "description": "ListDatabases succeeds", - "operations": [ - { - "name": "listDatabases", - "object": "client" - } - ], - "expectations": [ - { - "command_started_event": { - "command_name": "listDatabases", - "database_name": "admin", - "command": { - "listDatabases": 1 - } - } - } - ] - } - ] -} diff --git a/tests/SpecTests/atlas_data_lake/runCommand.json b/tests/SpecTests/atlas_data_lake/runCommand.json deleted file mode 100644 index d81ff1a64..000000000 --- a/tests/SpecTests/atlas_data_lake/runCommand.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "database_name": "test", - "tests": [ - { - "description": "ping succeeds using runCommand", - "operations": [ - { - "name": "runCommand", - "object": "database", - "command_name": "ping", - "arguments": { - "command": { - "ping": 1 - } - } - } - ], - "expectations": [ - { - "command_started_event": { - "command_name": "ping", - "database_name": "test", - "command": { - "ping": 1 - } - } - } - ] - } - ] -} diff --git a/tests/UnifiedSpecTests/UnifiedSpecTest.php b/tests/UnifiedSpecTests/UnifiedSpecTest.php index 0312044f6..3fa8054fa 100644 --- a/tests/UnifiedSpecTests/UnifiedSpecTest.php +++ b/tests/UnifiedSpecTests/UnifiedSpecTest.php @@ -213,6 +213,24 @@ public function setUp(): void } } + /** + * @dataProvider provideAtlasDataLakeTests + * @group atlas-data-lake + */ + public function testAtlasDataLake(UnifiedTestCase $test): void + { + if (! $this->isAtlasDataLake()) { + $this->markTestSkipped('Server is not Atlas Data Lake'); + } + + self::$runner->run($test); + } + + public function provideAtlasDataLakeTests() + { + return $this->provideTests(__DIR__ . '/atlas-data-lake/*.json'); + } + /** @dataProvider provideChangeStreamsTests */ public function testChangeStreams(UnifiedTestCase $test): void { diff --git a/tests/UnifiedSpecTests/atlas-data-lake/aggregate.json b/tests/UnifiedSpecTests/atlas-data-lake/aggregate.json new file mode 100644 index 000000000..68a3467c7 --- /dev/null +++ b/tests/UnifiedSpecTests/atlas-data-lake/aggregate.json @@ -0,0 +1,84 @@ +{ + "description": "aggregate", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "driverdata" + } + } + ], + "tests": [ + { + "description": "Aggregate with pipeline (project, sort, limit)", + "operations": [ + { + "object": "collection0", + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$project": { + "_id": 0 + } + }, + { + "$sort": { + "a": 1 + } + }, + { + "$limit": 2 + } + ] + }, + "expectResult": [ + { + "a": 1, + "b": 2, + "c": 3 + }, + { + "a": 2, + "b": 3, + "c": 4 + } + ] + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "aggregate": "driverdata" + }, + "commandName": "aggregate", + "databaseName": "test" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/atlas-data-lake/estimatedDocumentCount.json b/tests/UnifiedSpecTests/atlas-data-lake/estimatedDocumentCount.json new file mode 100644 index 000000000..b7515a441 --- /dev/null +++ b/tests/UnifiedSpecTests/atlas-data-lake/estimatedDocumentCount.json @@ -0,0 +1,56 @@ +{ + "description": "estimatedDocumentCount", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "driverdata" + } + } + ], + "tests": [ + { + "description": "estimatedDocumentCount succeeds", + "operations": [ + { + "object": "collection0", + "name": "estimatedDocumentCount", + "expectResult": 15 + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "count": "driverdata" + }, + "commandName": "count", + "databaseName": "test" + } + } + ] + } + ] + } + ] +} diff --git a/tests/SpecTests/atlas_data_lake/find.json b/tests/UnifiedSpecTests/atlas-data-lake/find.json similarity index 52% rename from tests/SpecTests/atlas_data_lake/find.json rename to tests/UnifiedSpecTests/atlas-data-lake/find.json index 8a3468a13..d0652dc72 100644 --- a/tests/SpecTests/atlas_data_lake/find.json +++ b/tests/UnifiedSpecTests/atlas-data-lake/find.json @@ -1,12 +1,36 @@ { - "collection_name": "driverdata", - "database_name": "test", + "description": "find", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "driverdata" + } + } + ], "tests": [ { "description": "Find with projection and sort", "operations": [ { - "object": "collection", + "object": "collection0", "name": "find", "arguments": { "filter": { @@ -22,7 +46,7 @@ }, "limit": 5 }, - "result": [ + "expectResult": [ { "a": 5, "b": 6, @@ -51,13 +75,20 @@ ] } ], - "expectations": [ + "expectEvents": [ { - "command_started_event": { - "command": { - "find": "driverdata" + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "driverdata" + }, + "commandName": "find", + "databaseName": "test" + } } - } + ] } ] } diff --git a/tests/UnifiedSpecTests/atlas-data-lake/getMore.json b/tests/UnifiedSpecTests/atlas-data-lake/getMore.json new file mode 100644 index 000000000..109b6d3d8 --- /dev/null +++ b/tests/UnifiedSpecTests/atlas-data-lake/getMore.json @@ -0,0 +1,95 @@ +{ + "description": "getMore", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "driverdata" + } + } + ], + "tests": [ + { + "description": "A successful find event with getMore", + "operations": [ + { + "object": "collection0", + "name": "find", + "arguments": { + "filter": { + "a": { + "$gte": 2 + } + }, + "sort": { + "a": 1 + }, + "batchSize": 3, + "limit": 4 + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "driverdata", + "filter": { + "a": { + "$gte": 2 + } + }, + "sort": { + "a": 1 + }, + "batchSize": 3, + "limit": 4 + }, + "commandName": "find", + "databaseName": "test" + } + }, + { + "commandStartedEvent": { + "command": { + "getMore": { + "$$type": [ + "int", + "long" + ] + }, + "collection": { + "$$type": "string" + }, + "batchSize": 1 + }, + "commandName": "getMore", + "databaseName": "cursors" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/atlas-data-lake/listCollections.json b/tests/UnifiedSpecTests/atlas-data-lake/listCollections.json new file mode 100644 index 000000000..642e7ed32 --- /dev/null +++ b/tests/UnifiedSpecTests/atlas-data-lake/listCollections.json @@ -0,0 +1,48 @@ +{ + "description": "listCollections", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + } + ], + "tests": [ + { + "description": "ListCollections succeeds", + "operations": [ + { + "object": "database0", + "name": "listCollections" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listCollections": 1 + }, + "commandName": "listCollections", + "databaseName": "test" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/atlas-data-lake/listDatabases.json b/tests/UnifiedSpecTests/atlas-data-lake/listDatabases.json new file mode 100644 index 000000000..64506ee54 --- /dev/null +++ b/tests/UnifiedSpecTests/atlas-data-lake/listDatabases.json @@ -0,0 +1,41 @@ +{ + "description": "listDatabases", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + } + ], + "tests": [ + { + "description": "ListCollections succeeds", + "operations": [ + { + "object": "client0", + "name": "listDatabases" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "listDatabases": 1 + }, + "commandName": "listDatabases", + "databaseName": "admin" + } + } + ] + } + ] + } + ] +} diff --git a/tests/UnifiedSpecTests/atlas-data-lake/runCommand.json b/tests/UnifiedSpecTests/atlas-data-lake/runCommand.json new file mode 100644 index 000000000..325b6b3f3 --- /dev/null +++ b/tests/UnifiedSpecTests/atlas-data-lake/runCommand.json @@ -0,0 +1,54 @@ +{ + "description": "runCommand", + "schemaVersion": "1.0", + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "test" + } + } + ], + "tests": [ + { + "description": "ping succeeds using runCommand", + "operations": [ + { + "object": "database0", + "name": "runCommand", + "arguments": { + "command": { + "ping": 1 + }, + "commandName": "ping" + } + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "ping": 1 + }, + "commandName": "ping", + "databaseName": "test" + } + } + ] + } + ] + } + ] +} From edf74da00130625346667be45c1486217b327534 Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Mon, 11 Mar 2024 10:40:44 -0400 Subject: [PATCH 2/2] Do not execute killAllSessions on Atlas Data Lake --- tests/UnifiedSpecTests/UnifiedTestRunner.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/UnifiedSpecTests/UnifiedTestRunner.php b/tests/UnifiedSpecTests/UnifiedTestRunner.php index 1ca5c4e1a..75f795875 100644 --- a/tests/UnifiedSpecTests/UnifiedTestRunner.php +++ b/tests/UnifiedSpecTests/UnifiedTestRunner.php @@ -82,8 +82,11 @@ 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 ($this->isServerless() || FunctionalTestCase::isAtlas($internalClientUri)) { + * mean that lingering transactions could block test execution. + * + * Atlas Data Lake also does not support killAllSessions. + */ + if ($this->isServerless() || FunctionalTestCase::isAtlas($internalClientUri) || $this->isAtlasDataLake()) { $this->allowKillAllSessions = false; } @@ -314,6 +317,14 @@ private function getTopology(): string } } + private function isAtlasDataLake(): bool + { + $database = $this->internalClient->selectDatabase('admin'); + $buildInfo = $database->command(['buildInfo' => 1])->toArray()[0]; + + return ! empty($buildInfo->dataLake); + } + /** * Return whether the connection is authenticated. *