From 4fc92788109ae3b06bf25a53d41a5b5fd242437e Mon Sep 17 00:00:00 2001 From: Jeremy Mikola Date: Fri, 7 Oct 2022 17:06:22 +0800 Subject: [PATCH] PHPLIB-909: expectedError.errorResponse assertion 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" + } + } + } + } + ] + } + ] +}