diff --git a/test/spec/read-write-concern/README.rst b/test/spec/read-write-concern/README.rst new file mode 100644 index 0000000000..5995590136 --- /dev/null +++ b/test/spec/read-write-concern/README.rst @@ -0,0 +1,80 @@ +======================= +Connection String Tests +======================= + +The YAML and JSON files in this directory tree are platform-independent tests +that drivers can use to prove their conformance to the Read and Write Concern +specification. + +Version +------- + +Files in the "specifications" repository have no version scheme. They are not +tied to a MongoDB server version. + +Format +------ + +Connection String +~~~~~~~~~~~~~~~~~ + +These tests are designed to exercise the connection string parsing related +to read concern and write concern. + +Each YAML file contains an object with a single ``tests`` key. This key is an +array of test case objects, each of which have the following keys: + +- ``description``: A string describing the test. +- ``uri``: A string containing the URI to be parsed. +- ``valid:``: a boolean indicating if parsing the uri should result in an error. +- ``writeConcern:`` A document indicating the expected write concern. +- ``readConcern:`` A document indicating the expected read concern. + +If a test case includes a null value for one of these keys, or if the key is missing, +no assertion is necessary. This both simplifies parsing of the test files and allows flexibility +for drivers that might substitute default values *during* parsing. + +Document +~~~~~~~~ + +These tests are designed to ensure compliance with the spec in relation to what should be +sent to the server. + +Each YAML file contains an object with a single ``tests`` key. This key is an +array of test case objects, each of which have the following keys: + +- ``description``: A string describing the test. +- ``valid:``: a boolean indicating if the write concern created from the document is valid. +- ``writeConcern:`` A document indicating the write concern to use. +- ``writeConcernDocument:`` A document indicating the write concern to be sent to the server. +- ``readConcern:`` A document indicating the read concern to use. +- ``readConcernDocument:`` A document indicating the read concern to be sent to the server. +- ``isServerDefault:`` Indicates whether the read or write concern is considered the server's default. +- ``isAcknowledged:`` Indicates if the write concern should be considered acknowledged. + +Operation +~~~~~~~~~ + +These tests check that the default write concern is omitted in operations. + +The spec test format is an extension of `transactions spec tests `_ with the following additions: + +- ``writeConcern`` in the ``databaseOptions`` or ``collectionOptions`` may be an empty document to indicate a `server default write concern `_. For example, in libmongoc: + + .. code:: c + + /* Create a default write concern, and set on a collection object. */ + mongoc_write_concern_t *wc = mongoc_write_concern_new (); + mongoc_collection_set_write_concern (collection, wc); + + If the driver has no way to explicitly set a default write concern on a database or collection, ignore the empty ``writeConcern`` document and continue with the test. +- The operations ``createIndex``, ``dropIndex`` are introduced. + + +Use as unit tests +================= + +Testing whether a URI is valid or not should simply be a matter of checking +whether URI parsing raises an error or exception. +Testing for emitted warnings may require more legwork (e.g. configuring a log +handler and watching for output). diff --git a/test/spec/read-write-concern/connection-string/read-concern.json b/test/spec/read-write-concern/connection-string/read-concern.json new file mode 100644 index 0000000000..1ecad8c268 --- /dev/null +++ b/test/spec/read-write-concern/connection-string/read-concern.json @@ -0,0 +1,47 @@ +{ + "tests": [ + { + "description": "Default", + "uri": "mongodb://localhost/", + "valid": true, + "warning": false, + "readConcern": {} + }, + { + "description": "local specified", + "uri": "mongodb://localhost/?readConcernLevel=local", + "valid": true, + "warning": false, + "readConcern": { + "level": "local" + } + }, + { + "description": "majority specified", + "uri": "mongodb://localhost/?readConcernLevel=majority", + "valid": true, + "warning": false, + "readConcern": { + "level": "majority" + } + }, + { + "description": "linearizable specified", + "uri": "mongodb://localhost/?readConcernLevel=linearizable", + "valid": true, + "warning": false, + "readConcern": { + "level": "linearizable" + } + }, + { + "description": "available specified", + "uri": "mongodb://localhost/?readConcernLevel=available", + "valid": true, + "warning": false, + "readConcern": { + "level": "available" + } + } + ] +} diff --git a/test/spec/read-write-concern/connection-string/read-concern.yml b/test/spec/read-write-concern/connection-string/read-concern.yml new file mode 100644 index 0000000000..499405fbae --- /dev/null +++ b/test/spec/read-write-concern/connection-string/read-concern.yml @@ -0,0 +1,32 @@ +tests: + - + description: "Default" + uri: "mongodb://localhost/" + valid: true + warning: false + readConcern: { } + - + description: "local specified" + uri: "mongodb://localhost/?readConcernLevel=local" + valid: true + warning: false + readConcern: { level: "local" } + - + description: "majority specified" + uri: "mongodb://localhost/?readConcernLevel=majority" + valid: true + warning: false + readConcern: { level: "majority" } + - + description: "linearizable specified" + uri: "mongodb://localhost/?readConcernLevel=linearizable" + valid: true + warning: false + readConcern: { level: "linearizable" } + - + description: "available specified" + uri: "mongodb://localhost/?readConcernLevel=available" + valid: true + warning: false + readConcern: { level: "available" } + diff --git a/test/spec/read-write-concern/connection-string/write-concern.json b/test/spec/read-write-concern/connection-string/write-concern.json new file mode 100644 index 0000000000..51bdf821c3 --- /dev/null +++ b/test/spec/read-write-concern/connection-string/write-concern.json @@ -0,0 +1,118 @@ +{ + "tests": [ + { + "description": "Default", + "uri": "mongodb://localhost/", + "valid": true, + "warning": false, + "writeConcern": {} + }, + { + "description": "w as a valid number", + "uri": "mongodb://localhost/?w=1", + "valid": true, + "warning": false, + "writeConcern": { + "w": 1 + } + }, + { + "description": "w as an invalid number", + "uri": "mongodb://localhost/?w=-2", + "valid": false, + "warning": null + }, + { + "description": "w as a string", + "uri": "mongodb://localhost/?w=majority", + "valid": true, + "warning": false, + "writeConcern": { + "w": "majority" + } + }, + { + "description": "wtimeoutMS as a valid number", + "uri": "mongodb://localhost/?wtimeoutMS=500", + "valid": true, + "warning": false, + "writeConcern": { + "wtimeoutMS": 500 + } + }, + { + "description": "wtimeoutMS as an invalid number", + "uri": "mongodb://localhost/?wtimeoutMS=-500", + "valid": false, + "warning": null + }, + { + "description": "journal as false", + "uri": "mongodb://localhost/?journal=false", + "valid": true, + "warning": false, + "writeConcern": { + "journal": false + } + }, + { + "description": "journal as true", + "uri": "mongodb://localhost/?journal=true", + "valid": true, + "warning": false, + "writeConcern": { + "journal": true + } + }, + { + "description": "All options combined", + "uri": "mongodb://localhost/?w=3&wtimeoutMS=500&journal=true", + "valid": true, + "warning": false, + "writeConcern": { + "w": 3, + "wtimeoutMS": 500, + "journal": true + } + }, + { + "description": "Unacknowledged with w", + "uri": "mongodb://localhost/?w=0", + "valid": true, + "warning": false, + "writeConcern": { + "w": 0 + } + }, + { + "description": "Unacknowledged with w and journal", + "uri": "mongodb://localhost/?w=0&journal=false", + "valid": true, + "warning": false, + "writeConcern": { + "w": 0, + "journal": false + } + }, + { + "description": "Unacknowledged with w and wtimeoutMS", + "uri": "mongodb://localhost/?w=0&wtimeoutMS=500", + "valid": true, + "warning": false, + "writeConcern": { + "w": 0, + "wtimeoutMS": 500 + } + }, + { + "description": "Acknowledged with w as 0 and journal true", + "uri": "mongodb://localhost/?w=0&journal=true", + "valid": false, + "warning": false, + "writeConcern": { + "w": 0, + "journal": true + } + } + ] +} diff --git a/test/spec/read-write-concern/connection-string/write-concern.yml b/test/spec/read-write-concern/connection-string/write-concern.yml new file mode 100644 index 0000000000..ca61085865 --- /dev/null +++ b/test/spec/read-write-concern/connection-string/write-concern.yml @@ -0,0 +1,77 @@ +tests: + - + description: "Default" + uri: "mongodb://localhost/" + valid: true + warning: false + writeConcern: { } + - + description: "w as a valid number" + uri: "mongodb://localhost/?w=1" + valid: true + warning: false + writeConcern: { w: 1 } + - + description: "w as an invalid number" + uri: "mongodb://localhost/?w=-2" + valid: false + warning: ~ + - + description: "w as a string" + uri: "mongodb://localhost/?w=majority" + valid: true + warning: false + writeConcern: { w: "majority" } + - + description: "wtimeoutMS as a valid number" + uri: "mongodb://localhost/?wtimeoutMS=500" + valid: true + warning: false + writeConcern: { wtimeoutMS: 500 } + - + description: "wtimeoutMS as an invalid number" + uri: "mongodb://localhost/?wtimeoutMS=-500" + valid: false + warning: ~ + - + description: "journal as false" + uri: "mongodb://localhost/?journal=false" + valid: true + warning: false + writeConcern: { journal: false } + - + description: "journal as true" + uri: "mongodb://localhost/?journal=true" + valid: true + warning: false + writeConcern: { journal: true } + - + description: "All options combined" + uri: "mongodb://localhost/?w=3&wtimeoutMS=500&journal=true" + valid: true + warning: false + writeConcern: { w: 3, wtimeoutMS: 500, journal: true } + - + description: "Unacknowledged with w" + uri: "mongodb://localhost/?w=0" + valid: true + warning: false + writeConcern: { w: 0 } + - + description: "Unacknowledged with w and journal" + uri: "mongodb://localhost/?w=0&journal=false" + valid: true + warning: false + writeConcern: { w: 0, journal: false } + - + description: "Unacknowledged with w and wtimeoutMS" + uri: "mongodb://localhost/?w=0&wtimeoutMS=500" + valid: true + warning: false + writeConcern: { w: 0, wtimeoutMS: 500 } + - + description: "Acknowledged with w as 0 and journal true" + uri: "mongodb://localhost/?w=0&journal=true" + valid: false + warning: false + writeConcern: { w: 0, journal: true } diff --git a/test/spec/read-write-concern/document/read-concern.json b/test/spec/read-write-concern/document/read-concern.json new file mode 100644 index 0000000000..187397dae5 --- /dev/null +++ b/test/spec/read-write-concern/document/read-concern.json @@ -0,0 +1,66 @@ +{ + "tests": [ + { + "description": "Default", + "valid": true, + "readConcern": {}, + "readConcernDocument": {}, + "isServerDefault": true + }, + { + "description": "Majority", + "valid": true, + "readConcern": { + "level": "majority" + }, + "readConcernDocument": { + "level": "majority" + }, + "isServerDefault": false + }, + { + "description": "Local", + "valid": true, + "readConcern": { + "level": "local" + }, + "readConcernDocument": { + "level": "local" + }, + "isServerDefault": false + }, + { + "description": "Linearizable", + "valid": true, + "readConcern": { + "level": "linearizable" + }, + "readConcernDocument": { + "level": "linearizable" + }, + "isServerDefault": false + }, + { + "description": "Snapshot", + "valid": true, + "readConcern": { + "level": "snapshot" + }, + "readConcernDocument": { + "level": "snapshot" + }, + "isServerDefault": false + }, + { + "description": "Available", + "valid": true, + "readConcern": { + "level": "available" + }, + "readConcernDocument": { + "level": "available" + }, + "isServerDefault": false + } + ] +} diff --git a/test/spec/read-write-concern/document/read-concern.yml b/test/spec/read-write-concern/document/read-concern.yml new file mode 100644 index 0000000000..7d774752d9 --- /dev/null +++ b/test/spec/read-write-concern/document/read-concern.yml @@ -0,0 +1,37 @@ +tests: + - + description: "Default" + valid: true + readConcern: {} + readConcernDocument: {} + isServerDefault: true + - + description: "Majority" + valid: true + readConcern: { level: "majority" } + readConcernDocument: { level: "majority" } + isServerDefault: false + - + description: "Local" + valid: true + readConcern: { level: "local" } + readConcernDocument: { level: "local" } + isServerDefault: false + - + description: "Linearizable" + valid: true + readConcern: { level: "linearizable" } + readConcernDocument: { level: "linearizable" } + isServerDefault: false + - + description: "Snapshot" + valid: true + readConcern: { level: "snapshot" } + readConcernDocument: {level: "snapshot" } + isServerDefault: false + - + description: "Available" + valid: true + readConcern: { level: "available" } + readConcernDocument: { level: "available" } + isServerDefault: false diff --git a/test/spec/read-write-concern/document/write-concern.json b/test/spec/read-write-concern/document/write-concern.json new file mode 100644 index 0000000000..64cd5d0eae --- /dev/null +++ b/test/spec/read-write-concern/document/write-concern.json @@ -0,0 +1,174 @@ +{ + "tests": [ + { + "description": "Default", + "valid": true, + "writeConcern": {}, + "writeConcernDocument": {}, + "isServerDefault": true, + "isAcknowledged": true + }, + { + "description": "W as a number", + "valid": true, + "writeConcern": { + "w": 3 + }, + "writeConcernDocument": { + "w": 3 + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "W as an invalid number", + "valid": false, + "writeConcern": { + "w": -3 + }, + "writeConcernDocument": null, + "isServerDefault": null, + "isAcknowledged": null + }, + { + "description": "W as majority", + "valid": true, + "writeConcern": { + "w": "majority" + }, + "writeConcernDocument": { + "w": "majority" + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "W as a custom string", + "valid": true, + "writeConcern": { + "w": "my_mode" + }, + "writeConcernDocument": { + "w": "my_mode" + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "WTimeoutMS", + "valid": true, + "writeConcern": { + "wtimeoutMS": 1000 + }, + "writeConcernDocument": { + "wtimeout": 1000 + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "WTimeoutMS as an invalid number", + "valid": false, + "writeConcern": { + "wtimeoutMS": -1000 + }, + "writeConcernDocument": null, + "isServerDefault": null, + "isAcknowledged": null + }, + { + "description": "Journal as true", + "valid": true, + "writeConcern": { + "journal": true + }, + "writeConcernDocument": { + "j": true + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "Journal as false", + "valid": true, + "writeConcern": { + "journal": false + }, + "writeConcernDocument": { + "j": false + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "Unacknowledged with only w", + "valid": true, + "writeConcern": { + "w": 0 + }, + "writeConcernDocument": { + "w": 0 + }, + "isServerDefault": false, + "isAcknowledged": false + }, + { + "description": "Unacknowledged with wtimeoutMS", + "valid": true, + "writeConcern": { + "w": 0, + "wtimeoutMS": 500 + }, + "writeConcernDocument": { + "w": 0, + "wtimeout": 500 + }, + "isServerDefault": false, + "isAcknowledged": false + }, + { + "description": "Unacknowledged with journal", + "valid": true, + "writeConcern": { + "w": 0, + "journal": false + }, + "writeConcernDocument": { + "w": 0, + "j": false + }, + "isServerDefault": false, + "isAcknowledged": false + }, + { + "description": "W is 0 with journal true", + "valid": false, + "writeConcern": { + "w": 0, + "journal": true + }, + "writeConcernDocument": { + "w": 0, + "j": true + }, + "isServerDefault": false, + "isAcknowledged": true + }, + { + "description": "Everything", + "valid": true, + "writeConcern": { + "w": 3, + "wtimeoutMS": 1000, + "journal": true + }, + "writeConcernDocument": { + "w": 3, + "wtimeout": 1000, + "j": true + }, + "isServerDefault": false, + "isAcknowledged": true + } + ] +} diff --git a/test/spec/read-write-concern/document/write-concern.yml b/test/spec/read-write-concern/document/write-concern.yml new file mode 100644 index 0000000000..bd82fdd59d --- /dev/null +++ b/test/spec/read-write-concern/document/write-concern.yml @@ -0,0 +1,99 @@ +tests: + - + description: "Default" + valid: true + writeConcern: {} + writeConcernDocument: {} + isServerDefault: true + isAcknowledged: true + - + description: "W as a number" + valid: true + writeConcern: { w: 3 } + writeConcernDocument: { w: 3 } + isServerDefault: false + isAcknowledged: true + - + description: "W as an invalid number" + valid: false + writeConcern: { w: -3 } + writeConcernDocument: ~ + isServerDefault: ~ + isAcknowledged: ~ + - + description: "W as majority" + valid: true + writeConcern: { w: "majority" } + writeConcernDocument: { w: "majority" } + isServerDefault: false + isAcknowledged: true + - + description: "W as a custom string" + valid: true + writeConcern: { w: "my_mode" } + writeConcernDocument: { w: "my_mode" } + isServerDefault: false + isAcknowledged: true + - + description: "WTimeoutMS" + valid: true + writeConcern: { wtimeoutMS: 1000 } + writeConcernDocument: { wtimeout: 1000 } + isServerDefault: false + isAcknowledged: true + - + description: "WTimeoutMS as an invalid number" + valid: false + writeConcern: { wtimeoutMS: -1000 } + writeConcernDocument: ~ + isServerDefault: ~ + isAcknowledged: ~ + - + description: "Journal as true" + valid: true + writeConcern: { journal: true } + writeConcernDocument: { j: true } + isServerDefault: false + isAcknowledged: true + - + description: "Journal as false" + valid: true + writeConcern: { journal: false } + writeConcernDocument: { j: false } + isServerDefault: false + isAcknowledged: true + - + description: "Unacknowledged with only w" + valid: true + writeConcern: { w: 0 } + writeConcernDocument: { w: 0 } + isServerDefault: false + isAcknowledged: false + - + description: "Unacknowledged with wtimeoutMS" + valid: true + writeConcern: { w: 0, wtimeoutMS: 500 } + writeConcernDocument: { w: 0, wtimeout: 500 } + isServerDefault: false + isAcknowledged: false + - + description: "Unacknowledged with journal" + valid: true + writeConcern: { w: 0, journal: false } + writeConcernDocument: { w: 0, j: false } + isServerDefault: false + isAcknowledged: false + - + description: "W is 0 with journal true" + valid: false + writeConcern: { w: 0, journal: true } + writeConcernDocument: { w: 0, j: true } + isServerDefault: false + isAcknowledged: true + - + description: "Everything" + valid: true + writeConcern: { w: 3, wtimeoutMS: 1000, journal: true } + writeConcernDocument: { w: 3, wtimeout: 1000, j: true } + isServerDefault: false + isAcknowledged: true diff --git a/test/spec/read-write-concern/operation/default-write-concern-2.6.json b/test/spec/read-write-concern/operation/default-write-concern-2.6.json new file mode 100644 index 0000000000..c623298cd7 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-2.6.json @@ -0,0 +1,544 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "collection_name": "default_write_concern_coll", + "database_name": "default_write_concern_db", + "runOn": [ + { + "minServerVersion": "2.6" + } + ], + "tests": [ + { + "description": "DeleteOne omits default write concern", + "operations": [ + { + "name": "deleteOne", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": {} + }, + "result": { + "deletedCount": 1 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "delete": "default_write_concern_coll", + "deletes": [ + { + "q": {}, + "limit": 1 + } + ], + "writeConcern": null + } + } + } + ] + }, + { + "description": "DeleteMany omits default write concern", + "operations": [ + { + "name": "deleteMany", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": {} + }, + "result": { + "deletedCount": 2 + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "delete": "default_write_concern_coll", + "deletes": [ + { + "q": {}, + "limit": 0 + } + ], + "writeConcern": null + } + } + } + ] + }, + { + "description": "BulkWrite with all models omits default write concern", + "operations": [ + { + "name": "bulkWrite", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "ordered": true, + "requests": [ + { + "name": "deleteMany", + "arguments": { + "filter": {} + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1 + } + } + }, + { + "name": "updateOne", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 2 + } + } + }, + { + "name": "replaceOne", + "arguments": { + "filter": { + "_id": 1 + }, + "replacement": { + "x": 2 + } + } + }, + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 3 + } + } + }, + { + "name": "updateMany", + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 3 + } + } + } + }, + { + "name": "deleteOne", + "arguments": { + "filter": { + "_id": 3 + } + } + } + ] + } + } + ], + "outcome": { + "collection": { + "name": "default_write_concern_coll", + "data": [ + { + "_id": 1, + "x": 3 + }, + { + "_id": 2 + } + ] + } + }, + "expectations": [ + { + "command_started_event": { + "command": { + "delete": "default_write_concern_coll", + "deletes": [ + { + "q": {}, + "limit": 0 + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "insert": "default_write_concern_coll", + "documents": [ + { + "_id": 1 + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "update": "default_write_concern_coll", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 1 + } + } + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "insert": "default_write_concern_coll", + "documents": [ + { + "_id": 2 + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "update": "default_write_concern_coll", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "x": 2 + } + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "insert": "default_write_concern_coll", + "documents": [ + { + "_id": 3 + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "update": "default_write_concern_coll", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 3 + } + }, + "multi": true + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "delete": "default_write_concern_coll", + "deletes": [ + { + "q": { + "_id": 3 + }, + "limit": 1 + } + ], + "writeConcern": null + } + } + } + ] + }, + { + "description": "InsertOne and InsertMany omit default write concern", + "operations": [ + { + "name": "insertOne", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "document": { + "_id": 3 + } + } + }, + { + "name": "insertMany", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "documents": [ + { + "_id": 4 + }, + { + "_id": 5 + } + ] + } + } + ], + "outcome": { + "collection": { + "name": "default_write_concern_coll", + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + }, + { + "_id": 3 + }, + { + "_id": 4 + }, + { + "_id": 5 + } + ] + } + }, + "expectations": [ + { + "command_started_event": { + "command": { + "insert": "default_write_concern_coll", + "documents": [ + { + "_id": 3 + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "insert": "default_write_concern_coll", + "documents": [ + { + "_id": 4 + }, + { + "_id": 5 + } + ], + "writeConcern": null + } + } + } + ] + }, + { + "description": "UpdateOne, UpdateMany, and ReplaceOne omit default write concern", + "operations": [ + { + "name": "updateOne", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "updateMany", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": { + "_id": 2 + }, + "update": { + "$set": { + "x": 2 + } + } + } + }, + { + "name": "replaceOne", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": { + "_id": 2 + }, + "replacement": { + "x": 3 + } + } + } + ], + "outcome": { + "collection": { + "name": "default_write_concern_coll", + "data": [ + { + "_id": 1, + "x": 1 + }, + { + "_id": 2, + "x": 3 + } + ] + } + }, + "expectations": [ + { + "command_started_event": { + "command": { + "update": "default_write_concern_coll", + "updates": [ + { + "q": { + "_id": 1 + }, + "u": { + "$set": { + "x": 1 + } + } + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "update": "default_write_concern_coll", + "updates": [ + { + "q": { + "_id": 2 + }, + "u": { + "$set": { + "x": 2 + } + }, + "multi": true + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "update": "default_write_concern_coll", + "updates": [ + { + "q": { + "_id": 2 + }, + "u": { + "x": 3 + } + } + ], + "writeConcern": null + } + } + } + ] + } + ] +} diff --git a/test/spec/read-write-concern/operation/default-write-concern-2.6.yml b/test/spec/read-write-concern/operation/default-write-concern-2.6.yml new file mode 100644 index 0000000000..725bcfca12 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-2.6.yml @@ -0,0 +1,215 @@ +# Test that setting a default write concern does not add a write concern +# to the command sent over the wire. +# Test operations that require 2.6+ server. + +data: + - {_id: 1, x: 11} + - {_id: 2, x: 22} +collection_name: &collection_name default_write_concern_coll +database_name: &database_name default_write_concern_db + +runOn: + - minServerVersion: "2.6" + +tests: + - description: DeleteOne omits default write concern + operations: + - name: deleteOne + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {} + result: + deletedCount: 1 + expectations: + - command_started_event: + command: + delete: *collection_name + deletes: + - {q: {}, limit: 1} + writeConcern: null + - description: DeleteMany omits default write concern + operations: + - name: deleteMany + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {} + result: + deletedCount: 2 + expectations: + - command_started_event: + command: + delete: *collection_name + deletes: [{q: {}, limit: 0}] + writeConcern: null + - description: BulkWrite with all models omits default write concern + operations: + - name: bulkWrite + object: collection + collectionOptions: {writeConcern: {}} + arguments: + ordered: true + requests: + - name: deleteMany + arguments: + filter: {} + - name: insertOne + arguments: + document: {_id: 1} + - name: updateOne + arguments: + filter: {_id: 1} + update: {$set: {x: 1}} + - name: insertOne + arguments: + document: {_id: 2} + - name: replaceOne + arguments: + filter: {_id: 1} + replacement: {x: 2} + - name: insertOne + arguments: + document: {_id: 3} + - name: updateMany + arguments: + filter: {_id: 1} + update: {$set: {x: 3}} + - name: deleteOne + arguments: + filter: {_id: 3} + outcome: + collection: + name: *collection_name + data: + - {_id: 1, x: 3} + - {_id: 2} + expectations: + - command_started_event: + command: + delete: *collection_name + deletes: [{q: {}, limit: 0}] + writeConcern: null + - command_started_event: + command: + insert: *collection_name + documents: + - {_id: 1} + writeConcern: null + - command_started_event: + command: + update: *collection_name + updates: + - {q: {_id: 1}, u: {$set: {x: 1}}} + writeConcern: null + - command_started_event: + command: + insert: *collection_name + documents: + - {_id: 2} + writeConcern: null + - command_started_event: + command: + update: *collection_name + updates: + - {q: {_id: 1}, u: {x: 2}} + writeConcern: null + - command_started_event: + command: + insert: *collection_name + documents: + - {_id: 3} + writeConcern: null + - command_started_event: + command: + update: *collection_name + updates: + - {q: {_id: 1}, u: {$set: {x: 3}}, multi: true} + writeConcern: null + - command_started_event: + command: + delete: *collection_name + deletes: [{q: {_id: 3}, limit: 1}] + writeConcern: null + - description: 'InsertOne and InsertMany omit default write concern' + operations: + - name: insertOne + object: collection + collectionOptions: {writeConcern: {}} + arguments: + document: {_id: 3} + - name: insertMany + object: collection + collectionOptions: {writeConcern: {}} + arguments: + documents: + - {_id: 4} + - {_id: 5} + outcome: + collection: + name: *collection_name + data: + - {_id: 1, x: 11} + - {_id: 2, x: 22} + - {_id: 3} + - {_id: 4} + - {_id: 5} + expectations: + - command_started_event: + command: + insert: *collection_name + documents: + - {_id: 3} + writeConcern: null + - command_started_event: + command: + insert: *collection_name + documents: + - {_id: 4} + - {_id: 5} + writeConcern: null + - description: 'UpdateOne, UpdateMany, and ReplaceOne omit default write concern' + operations: + - name: updateOne + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {_id: 1} + update: {$set: {x: 1}} + - name: updateMany + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {_id: 2} + update: {$set: {x: 2}} + - name: replaceOne + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {_id: 2} + replacement: {x: 3} + outcome: + collection: + name: *collection_name + data: + - {_id: 1, x: 1} + - {_id: 2, x: 3} + expectations: + - command_started_event: + command: + update: *collection_name + updates: + - {q: {_id: 1}, u: {$set: {x: 1}}} + writeConcern: null + - command_started_event: + command: + update: *collection_name + updates: + - {q: {_id: 2}, u: {$set: {x: 2}}, multi: true} + writeConcern: null + - command_started_event: + command: + update: *collection_name + updates: + - {q: {_id: 2}, u: {x: 3}} + writeConcern: null \ No newline at end of file diff --git a/test/spec/read-write-concern/operation/default-write-concern-3.2.json b/test/spec/read-write-concern/operation/default-write-concern-3.2.json new file mode 100644 index 0000000000..04dd231f04 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-3.2.json @@ -0,0 +1,125 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "collection_name": "default_write_concern_coll", + "database_name": "default_write_concern_db", + "runOn": [ + { + "minServerVersion": "3.2" + } + ], + "tests": [ + { + "description": "findAndModify operations omit default write concern", + "operations": [ + { + "name": "findOneAndUpdate", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + } + } + }, + { + "name": "findOneAndReplace", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": { + "_id": 2 + }, + "replacement": { + "x": 2 + } + } + }, + { + "name": "findOneAndDelete", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "filter": { + "_id": 2 + } + } + } + ], + "outcome": { + "collection": { + "name": "default_write_concern_coll", + "data": [ + { + "_id": 1, + "x": 1 + } + ] + } + }, + "expectations": [ + { + "command_started_event": { + "command": { + "findAndModify": "default_write_concern_coll", + "query": { + "_id": 1 + }, + "update": { + "$set": { + "x": 1 + } + }, + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default_write_concern_coll", + "query": { + "_id": 2 + }, + "update": { + "x": 2 + }, + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "findAndModify": "default_write_concern_coll", + "query": { + "_id": 2 + }, + "remove": true, + "writeConcern": null + } + } + } + ] + } + ] +} diff --git a/test/spec/read-write-concern/operation/default-write-concern-3.2.yml b/test/spec/read-write-concern/operation/default-write-concern-3.2.yml new file mode 100644 index 0000000000..dccb7e0d07 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-3.2.yml @@ -0,0 +1,58 @@ +# Test that setting a default write concern does not add a write concern +# to the command sent over the wire. +# Test operations that require 3.2+ server, where findAndModify started +# to accept a write concern. + +data: + - {_id: 1, x: 11} + - {_id: 2, x: 22} +collection_name: &collection_name default_write_concern_coll +database_name: &database_name default_write_concern_db + +runOn: + - minServerVersion: "3.2" + +tests: + - description: 'findAndModify operations omit default write concern' + operations: + - name: findOneAndUpdate + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {_id: 1} + update: {$set: {x: 1}} + - name: findOneAndReplace + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {_id: 2} + replacement: {x: 2} + - name: findOneAndDelete + object: collection + collectionOptions: {writeConcern: {}} + arguments: + filter: {_id: 2} + outcome: + collection: + name: *collection_name + data: + - {_id: 1, x: 1} + expectations: + - command_started_event: + command: + findAndModify: *collection_name + query: {_id: 1} + update: {$set: {x: 1}} + writeConcern: null + - command_started_event: + command: + findAndModify: *collection_name + query: {_id: 2} + update: {x: 2} + writeConcern: null + - command_started_event: + command: + findAndModify: *collection_name + query: {_id: 2} + remove: true + writeConcern: null \ No newline at end of file diff --git a/test/spec/read-write-concern/operation/default-write-concern-3.4.json b/test/spec/read-write-concern/operation/default-write-concern-3.4.json new file mode 100644 index 0000000000..6519f6f089 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-3.4.json @@ -0,0 +1,216 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "collection_name": "default_write_concern_coll", + "database_name": "default_write_concern_db", + "runOn": [ + { + "minServerVersion": "3.4" + } + ], + "tests": [ + { + "description": "Aggregate with $out omits default write concern", + "operations": [ + { + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_collection_name" + } + ] + } + } + ], + "outcome": { + "collection": { + "name": "other_collection_name", + "data": [ + { + "_id": 2, + "x": 22 + } + ] + } + }, + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "default_write_concern_coll", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$out": "other_collection_name" + } + ], + "writeConcern": null + } + } + } + ] + }, + { + "description": "RunCommand with a write command omits default write concern (runCommand should never inherit write concern)", + "operations": [ + { + "object": "database", + "databaseOptions": { + "writeConcern": {} + }, + "name": "runCommand", + "command_name": "delete", + "arguments": { + "command": { + "delete": "default_write_concern_coll", + "deletes": [ + { + "q": {}, + "limit": 1 + } + ] + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "delete": "default_write_concern_coll", + "deletes": [ + { + "q": {}, + "limit": 1 + } + ], + "writeConcern": null + } + } + } + ] + }, + { + "description": "CreateIndex and dropIndex omits default write concern", + "operations": [ + { + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "name": "createIndex", + "arguments": { + "keys": { + "x": 1 + } + } + }, + { + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "name": "dropIndex", + "arguments": { + "name": "x_1" + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "createIndexes": "default_write_concern_coll", + "indexes": [ + { + "name": "x_1", + "key": { + "x": 1 + } + } + ], + "writeConcern": null + } + } + }, + { + "command_started_event": { + "command": { + "dropIndexes": "default_write_concern_coll", + "index": "x_1", + "writeConcern": null + } + } + } + ] + }, + { + "description": "MapReduce omits default write concern", + "operations": [ + { + "name": "mapReduce", + "object": "collection", + "collectionOptions": { + "writeConcern": {} + }, + "arguments": { + "map": { + "$code": "function inc() { return emit(0, this.x + 1) }" + }, + "reduce": { + "$code": "function sum(key, values) { return values.reduce((acc, x) => acc + x); }" + }, + "out": { + "inline": 1 + } + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "mapReduce": "default_write_concern_coll", + "map": { + "$code": "function inc() { return emit(0, this.x + 1) }" + }, + "reduce": { + "$code": "function sum(key, values) { return values.reduce((acc, x) => acc + x); }" + }, + "out": { + "inline": 1 + }, + "writeConcern": null + } + } + } + ] + } + ] +} diff --git a/test/spec/read-write-concern/operation/default-write-concern-3.4.yml b/test/spec/read-write-concern/operation/default-write-concern-3.4.yml new file mode 100644 index 0000000000..c7b586cadc --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-3.4.yml @@ -0,0 +1,95 @@ +# Test that setting a default write concern does not add a write concern +# to the command sent over the wire. +# Test operations that require 3.4+ server, where all commands started +# to accept a write concern. + +data: + - {_id: 1, x: 11} + - {_id: 2, x: 22} +collection_name: &collection_name default_write_concern_coll +database_name: &database_name default_write_concern_db + +runOn: + - minServerVersion: "3.4" + +tests: + - description: Aggregate with $out omits default write concern + operations: + - object: collection + collectionOptions: {writeConcern: {}} + name: aggregate + arguments: + pipeline: &out_pipeline + - $match: {_id: {$gt: 1}} + - $out: &other_collection_name "other_collection_name" + outcome: + collection: + name: *other_collection_name + data: + - {_id: 2, x: 22} + expectations: + - command_started_event: + command: + aggregate: *collection_name + pipeline: *out_pipeline + writeConcern: null + - description: RunCommand with a write command omits default write concern (runCommand should never inherit write concern) + operations: + - object: database + databaseOptions: {writeConcern: {}} + name: runCommand + command_name: delete + arguments: + command: + delete: *collection_name + deletes: + - {q: {}, limit: 1} + expectations: + - command_started_event: + command: + delete: *collection_name + deletes: + - {q: {}, limit: 1} + writeConcern: null + - description: CreateIndex and dropIndex omits default write concern + operations: + - object: collection + collectionOptions: {writeConcern: {}} + name: createIndex + arguments: + keys: {x: 1} + - object: collection + collectionOptions: {writeConcern: {}} + name: dropIndex + arguments: + name: x_1 + expectations: + - command_started_event: + command: + createIndexes: *collection_name + indexes: + - name: x_1 + key: {x: 1} + writeConcern: null + - command_started_event: + command: + dropIndexes: *collection_name + index: x_1 + writeConcern: null + - description: MapReduce omits default write concern + operations: + - name: mapReduce + object: collection + collectionOptions: {writeConcern: {}} + arguments: + map: { $code: 'function inc() { return emit(0, this.x + 1) }' } + reduce: { $code: 'function sum(key, values) { return values.reduce((acc, x) => acc + x); }' } + out: { inline: 1 } + expectations: + - command_started_event: + command: + mapReduce: *collection_name + map: { $code: 'function inc() { return emit(0, this.x + 1) }' } + reduce: { $code: 'function sum(key, values) { return values.reduce((acc, x) => acc + x); }' } + out: { inline: 1 } + writeConcern: null \ No newline at end of file diff --git a/test/spec/read-write-concern/operation/default-write-concern-4.2.json b/test/spec/read-write-concern/operation/default-write-concern-4.2.json new file mode 100644 index 0000000000..fef192d1a3 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-4.2.json @@ -0,0 +1,87 @@ +{ + "data": [ + { + "_id": 1, + "x": 11 + }, + { + "_id": 2, + "x": 22 + } + ], + "collection_name": "default_write_concern_coll", + "database_name": "default_write_concern_db", + "runOn": [ + { + "minServerVersion": "4.2" + } + ], + "tests": [ + { + "description": "Aggregate with $merge omits default write concern", + "operations": [ + { + "object": "collection", + "databaseOptions": { + "writeConcern": {} + }, + "collectionOptions": { + "writeConcern": {} + }, + "name": "aggregate", + "arguments": { + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_collection_name" + } + } + ] + } + } + ], + "expectations": [ + { + "command_started_event": { + "command": { + "aggregate": "default_write_concern_coll", + "pipeline": [ + { + "$match": { + "_id": { + "$gt": 1 + } + } + }, + { + "$merge": { + "into": "other_collection_name" + } + } + ], + "writeConcern": null + } + } + } + ], + "outcome": { + "collection": { + "name": "other_collection_name", + "data": [ + { + "_id": 2, + "x": 22 + } + ] + } + } + } + ] +} diff --git a/test/spec/read-write-concern/operation/default-write-concern-4.2.yml b/test/spec/read-write-concern/operation/default-write-concern-4.2.yml new file mode 100644 index 0000000000..6039b55814 --- /dev/null +++ b/test/spec/read-write-concern/operation/default-write-concern-4.2.yml @@ -0,0 +1,36 @@ +# Test that setting a default write concern does not add a write concern +# to the command sent over the wire. +# Test operations that require 4.2+ server. + +data: + - {_id: 1, x: 11} + - {_id: 2, x: 22} +collection_name: &collection_name default_write_concern_coll +database_name: &database_name default_write_concern_db + +runOn: + - minServerVersion: "4.2" + +tests: + - description: Aggregate with $merge omits default write concern + operations: + - object: collection + databaseOptions: {writeConcern: {}} + collectionOptions: {writeConcern: {}} + name: aggregate + arguments: + pipeline: &merge_pipeline + - $match: {_id: {$gt: 1}} + - $merge: {into: &other_collection_name "other_collection_name" } + expectations: + - command_started_event: + command: + aggregate: *collection_name + pipeline: *merge_pipeline + # "null" fields will be checked for non-existence + writeConcern: null + outcome: + collection: + name: *other_collection_name + data: + - {_id: 2, x: 22} \ No newline at end of file